This patch introduces the capability to use a different iterator per variable. The currently supported notation of variables in a filtering rule like processes the two lists 'A' and 'B' in parallel. This means that A and B must have the same number of 'N' elements and that 'N' rules will be instantiated (assuming all tuples from A and B are unique). In this patch we now introduce the assignment of variables to different iterators. Therefore a rule like will now create every combination of elements in A with elements in B since A has been assigned to an iterator with Id '1' and B has been assigned to an iterator with Id '2', thus processing their value independently. The first rule has an equivalent notation of --- docs/schemas/nwfilter.rng | 71 ++------ src/conf/nwfilter_conf.c | 35 ++-- src/conf/nwfilter_conf.h | 6 src/conf/nwfilter_params.c | 240 +++++++++++++++++++++++++++--- src/conf/nwfilter_params.h | 38 ++++ src/libvirt_private.syms | 1 src/nwfilter/nwfilter_ebiptables_driver.c | 13 + src/nwfilter/nwfilter_gentech_driver.c | 8 - 8 files changed, 308 insertions(+), 104 deletions(-) Index: libvirt-iterator/src/conf/nwfilter_conf.h =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_conf.h +++ libvirt-iterator/src/conf/nwfilter_conf.h @@ -121,7 +121,7 @@ typedef struct _nwItemDesc nwItemDesc; typedef nwItemDesc *nwItemDescPtr; struct _nwItemDesc { enum virNWFilterEntryItemFlags flags; - char *var; + virNWFilterVarAccessPtr varAccess; enum attrDatatype datatype; union { nwMACAddress macaddr; @@ -470,8 +470,8 @@ struct _virNWFilterRuleDef { sctpHdrFilterDef sctpHdrFilter; } p; - int nvars; - char **vars; + size_t nVarAccess; + virNWFilterVarAccessPtr *varAccess; int nstrings; char **strings; Index: libvirt-iterator/src/conf/nwfilter_conf.c =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_conf.c +++ libvirt-iterator/src/conf/nwfilter_conf.c @@ -272,13 +272,13 @@ virNWFilterRuleDefFree(virNWFilterRuleDe if (!def) return; - for (i = 0; i < def->nvars; i++) - VIR_FREE(def->vars[i]); + for (i = 0; i < def->nVarAccess; i++) + virNWFilterVarAccessFree(def->varAccess[i]); for (i = 0; i < def->nstrings; i++) VIR_FREE(def->strings[i]); - VIR_FREE(def->vars); + VIR_FREE(def->varAccess); VIR_FREE(def->strings); VIR_FREE(def); @@ -358,28 +358,28 @@ virNWFilterRuleDefAddVar(virNWFilterRule const char *var) { int i = 0; + virNWFilterVarAccessPtr varAccess; - if (nwf->vars) { - for (i = 0; i < nwf->nvars; i++) - if (STREQ(nwf->vars[i], var)) { - item->var = nwf->vars[i]; + varAccess = virNWFilterVarAccessParse(var); + if (varAccess == NULL) + return -1; + + if (nwf->varAccess) { + for (i = 0; i < nwf->nVarAccess; i++) + if (virNWFilterVarAccessEqual(nwf->varAccess[i], varAccess)) { + virNWFilterVarAccessFree(varAccess); + item->varAccess = nwf->varAccess[i]; return 0; } } - if (VIR_REALLOC_N(nwf->vars, nwf->nvars+1) < 0) { - virReportOOMError(); - return -1; - } - - nwf->vars[nwf->nvars] = strdup(var); - - if (!nwf->vars[nwf->nvars]) { + if (VIR_EXPAND_N(nwf->varAccess, nwf->nVarAccess, 1) < 0) { virReportOOMError(); return -1; } - item->var = nwf->vars[nwf->nvars++]; + nwf->varAccess[nwf->nVarAccess - 1] = varAccess; + item->varAccess = varAccess; return 0; } @@ -3069,7 +3069,8 @@ virNWFilterRuleDefDetailsFormat(virBuffe goto err_exit; } } else if ((flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) { - virBufferAsprintf(buf, "$%s", item->var); + virBufferAddChar(buf, '$'); + virNWFilterVarAccessPrint(item->varAccess, buf); } else { asHex = false; Index: libvirt-iterator/src/conf/nwfilter_params.c =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.c +++ libvirt-iterator/src/conf/nwfilter_params.c @@ -310,10 +310,11 @@ virNWFilterVarCombIterEntryInit(virNWFil static int virNWFilterVarCombIterAddVariable(virNWFilterVarCombIterEntryPtr cie, virNWFilterHashTablePtr hash, - const char *varName) + const virNWFilterVarAccessPtr varAccess) { virNWFilterVarValuePtr varValue; unsigned int cardinality; + const char *varName = virNWFilterVarAccessGetVarName(varAccess); varValue = virHashLookup(hash->hashTable, varName); if (varValue == NULL) { @@ -409,13 +410,14 @@ virNWFilterVarCombIterEntryAreUniqueEntr */ virNWFilterVarCombIterPtr virNWFilterVarCombIterCreate(virNWFilterHashTablePtr hash, - char * const *vars, unsigned int nVars) + const virNWFilterVarAccessPtr *varAccess, + size_t nVarAccess) { virNWFilterVarCombIterPtr res; unsigned int i, iterId; - int iterIndex; + int iterIndex = -1; - if (VIR_ALLOC_VAR(res, virNWFilterVarCombIterEntry, 1) < 0) { + if (VIR_ALLOC_VAR(res, virNWFilterVarCombIterEntry, 1 + nVarAccess) < 0) { virReportOOMError(); return NULL; } @@ -428,22 +430,24 @@ virNWFilterVarCombIterCreate(virNWFilter res->nIter = 1; virNWFilterVarCombIterEntryInit(&res->iter[0], iterId); - for (i = 0; i < nVars; i++) { - - /* currently always access @0 */ - iterId = 0; - - iterIndex = virNWFilterVarCombIterGetIndexByIterId(res, iterId); - if (iterIndex < 0) { - /* future: create new iterator. for now it's a bug */ - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not find iterator with id %u"), - iterId); - goto err_exit; + for (i = 0; i < nVarAccess; i++) { + switch (virNWFilterVarAccessGetType(varAccess[i])) { + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + iterId = virNWFilterVarAccessGetIterId(varAccess[i]); + iterIndex = virNWFilterVarCombIterGetIndexByIterId(res, iterId); + if (iterIndex < 0) { + iterIndex = res->nIter; + virNWFilterVarCombIterEntryInit(&res->iter[iterIndex], iterId); + res->nIter++; + } + break; + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + case VIR_NWFILTER_VAR_ACCESS_LAST: + break; } if (virNWFilterVarCombIterAddVariable(&res->iter[iterIndex], - hash, vars[i]) < 0) + hash, varAccess[i]) < 0) goto err_exit; } @@ -482,16 +486,33 @@ next: const char * virNWFilterVarCombIterGetVarValue(virNWFilterVarCombIterPtr ci, - const char *varName) + const virNWFilterVarAccessPtr vap) { - unsigned int i; + unsigned int i, iterId; bool found = false; const char *res = NULL; virNWFilterVarValuePtr value; - unsigned int iterIndex; + int iterIndex = -1; + const char *varName = virNWFilterVarAccessGetVarName(vap); - /* currently always accessing iter @0 */ - iterIndex = 0; + switch (virNWFilterVarAccessGetType(vap)) { + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + iterId = virNWFilterVarAccessGetIterId(vap); + iterIndex = virNWFilterVarCombIterGetIndexByIterId(ci, iterId); + if (iterIndex < 0) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get iterator index for " + "iterator ID %u"), iterId); + return NULL; + } + break; + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Element access via index is not possible")); + return NULL; + case VIR_NWFILTER_VAR_ACCESS_LAST: + return NULL; + } for (i = 0; i < ci->iter[iterIndex].nVarNames; i++) { if (STREQ(ci->iter[iterIndex].varNames[i], varName)) { @@ -830,3 +851,178 @@ virNWFilterFormatParamAttributes(virBuff return 0; } + +void +virNWFilterVarAccessFree(virNWFilterVarAccessPtr varAccess) +{ + if (!varAccess) + return; + + VIR_FREE(varAccess->varName); + VIR_FREE(varAccess); +} + +bool +virNWFilterVarAccessEqual(const virNWFilterVarAccessPtr a, + const virNWFilterVarAccessPtr b) +{ + if (a->accessType != b->accessType) + return false; + + if (STRNEQ(a->varName, b->varName)) + return false; + + switch (a->accessType) { + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + return (a->u.index == b->u.index); + break; + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + return (a->u.iterId == b->u.iterId); + break; + case VIR_NWFILTER_VAR_ACCESS_LAST: + break; + } + return false; +} + +/* + * Parse a variable access like + * IP, IP[@2], IP[3] + */ +virNWFilterVarAccessPtr +virNWFilterVarAccessParse(const char *varAccess) +{ + size_t idx, varNameLen; + virNWFilterVarAccessPtr dest; + const char *input = varAccess; + + if (VIR_ALLOC(dest) < 0) { + virReportOOMError(); + return NULL; + } + + idx = strspn(input, VALID_VARNAME); + + if (input[idx] == '\0') { + /* in the form 'IP', which is equivalent to IP[@0] */ + dest->varName = strndup(input, idx); + if (!dest->varName) { + virReportOOMError(); + goto err_exit; + } + dest->accessType = VIR_NWFILTER_VAR_ACCESS_ITERATOR; + dest->u.iterId = 0; + return dest; + } + + if (input[idx] == '[') { + char *end_ptr; + unsigned int result; + bool parseError = false; + + varNameLen = idx; + + dest->varName = strndup(input, varNameLen); + if (!dest->varName) { + virReportOOMError(); + goto err_exit; + } + + input += idx + 1; + virSkipSpaces(&input); + + if (*input == '@') { + /* in the form 'IP[@] -> iterator */ + dest->accessType = VIR_NWFILTER_VAR_ACCESS_ITERATOR; + input++; + } else { + /* in the form 'IP[] -> element */ + dest->accessType = VIR_NWFILTER_VAR_ACCESS_ELEMENT; + /* not supported (yet) */ + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Variable access in the form " + "var[] is not supported")); + goto err_exit; + } + + if (virStrToLong_ui(input, &end_ptr, 10, &result) < 0) + parseError = true; + if (!parseError) { + input = end_ptr; + virSkipSpaces(&input); + if (*input != ']') + parseError = true; + } + if (parseError) { + if (dest->accessType == VIR_NWFILTER_VAR_ACCESS_ELEMENT) + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Malformatted array index")); + else + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Malformatted iterator id")); + goto err_exit; + } + + switch (dest->accessType) { + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + dest->u.index = result; + break; + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + if (result > VIR_NWFILTER_MAX_ITERID) { + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Iterator ID exceeds maximum ID " + "of %u"), VIR_NWFILTER_MAX_ITERID); + goto err_exit; + } + dest->u.iterId = result; + break; + case VIR_NWFILTER_VAR_ACCESS_LAST: + goto err_exit; + } + + return dest; + } else { + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Malformatted variable")); + } + +err_exit: + virNWFilterVarAccessFree(dest); + + return NULL; +} + +void +virNWFilterVarAccessPrint(virNWFilterVarAccessPtr vap, virBufferPtr buf) +{ + virBufferAdd(buf, vap->varName, -1); + switch (vap->accessType) { + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + virBufferAsprintf(buf, "[%u]", vap->u.index); + break; + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + if (vap->u.iterId != 0) + virBufferAsprintf(buf, "[@%u]", vap->u.iterId); + break; + case VIR_NWFILTER_VAR_ACCESS_LAST: + break; + } +} + +const char * +virNWFilterVarAccessGetVarName(const virNWFilterVarAccessPtr vap) +{ + return vap->varName; +} + +enum virNWFilterVarAccessType +virNWFilterVarAccessGetType(const virNWFilterVarAccessPtr vap) +{ + return vap->accessType; +} + +unsigned int +virNWFilterVarAccessGetIterId(const virNWFilterVarAccessPtr vap) +{ + return vap->u.iterId; +} Index: libvirt-iterator/src/conf/nwfilter_params.h =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.h +++ libvirt-iterator/src/conf/nwfilter_params.h @@ -91,6 +91,38 @@ int virNWFilterHashTablePutAll(virNWFilt # define VALID_VARVALUE \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.:" +enum virNWFilterVarAccessType { + VIR_NWFILTER_VAR_ACCESS_ELEMENT = 0, + VIR_NWFILTER_VAR_ACCESS_ITERATOR = 1, + + VIR_NWFILTER_VAR_ACCESS_LAST, +}; + +typedef struct _virNWFilterVarAccess virNWFilterVarAccess; +typedef virNWFilterVarAccess *virNWFilterVarAccessPtr; +struct _virNWFilterVarAccess { + enum virNWFilterVarAccessType accessType; + union { + unsigned int index; + unsigned int iterId; + } u; + char *varName; +}; + +# define VIR_NWFILTER_MAX_ITERID 1000 + +void virNWFilterVarAccessFree(virNWFilterVarAccessPtr varAccess); +bool virNWFilterVarAccessEqual(const virNWFilterVarAccessPtr a, + const virNWFilterVarAccessPtr b); +virNWFilterVarAccessPtr virNWFilterVarAccessParse(const char *varAccess); +void virNWFilterVarAccessPrint(virNWFilterVarAccessPtr vap, + virBufferPtr buf); +const char *virNWFilterVarAccessGetVarName(const virNWFilterVarAccessPtr vap); +enum virNWFilterVarAccessType virNWFilterVarAccessGetType( + const virNWFilterVarAccessPtr vap); +unsigned int virNWFilterVarAccessGetIterId(const virNWFilterVarAccessPtr vap); + + typedef struct _virNWFilterVarCombIterEntry virNWFilterVarCombIterEntry; typedef virNWFilterVarCombIterEntry *virNWFilterVarCombIterEntryPtr; struct _virNWFilterVarCombIterEntry { @@ -110,12 +142,14 @@ struct _virNWFilterVarCombIter { }; virNWFilterVarCombIterPtr virNWFilterVarCombIterCreate( virNWFilterHashTablePtr hash, - char * const *vars, unsigned int nVars); + const virNWFilterVarAccessPtr *vars, + size_t nVars); void virNWFilterVarCombIterFree(virNWFilterVarCombIterPtr ci); virNWFilterVarCombIterPtr virNWFilterVarCombIterNext( virNWFilterVarCombIterPtr ci); const char *virNWFilterVarCombIterGetVarValue(virNWFilterVarCombIterPtr ci, - const char *varname); + const virNWFilterVarAccessPtr); + #endif /* NWFILTER_PARAMS_H */ Index: libvirt-iterator/src/libvirt_private.syms =================================================================== --- libvirt-iterator.orig/src/libvirt_private.syms +++ libvirt-iterator/src/libvirt_private.syms @@ -832,6 +832,7 @@ virNWFilterHashTableFree; virNWFilterHashTablePut; virNWFilterHashTablePutAll; virNWFilterHashTableRemoveEntry; +virNWFilterVarAccessGetVarName; virNWFilterVarCombIterCreate; virNWFilterVarCombIterFree; virNWFilterVarCombIterGetVarValue; Index: libvirt-iterator/src/nwfilter/nwfilter_ebiptables_driver.c =================================================================== --- libvirt-iterator.orig/src/nwfilter/nwfilter_ebiptables_driver.c +++ libvirt-iterator/src/nwfilter/nwfilter_ebiptables_driver.c @@ -230,17 +230,19 @@ printVar(virNWFilterVarCombIterPtr vars, if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) { const char *val; - val = virNWFilterVarCombIterGetVarValue(vars, item->var); + val = virNWFilterVarCombIterGetVarValue(vars, item->varAccess); if (!val) { /* error has been reported */ return -1; } if (!virStrcpy(buf, val, bufsize)) { + const char *varName; + + varName = virNWFilterVarAccessGetVarName(item->varAccess); virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, - _("Buffer too small to print MAC address " - "'%s' into"), - item->var); + _("Buffer too small to print variable " + "'%s' into"), varName); return -1; } @@ -2631,7 +2633,8 @@ ebiptablesCreateRuleInstanceIterate( * iterate over all combinations of the variables' values and instantiate * the filtering rule with each combination. */ - vciter = virNWFilterVarCombIterCreate(vars, rule->vars, rule->nvars); + vciter = virNWFilterVarCombIterCreate(vars, + rule->varAccess, rule->nVarAccess); if (!vciter) return -1; Index: libvirt-iterator/src/nwfilter/nwfilter_gentech_driver.c =================================================================== --- libvirt-iterator.orig/src/nwfilter/nwfilter_gentech_driver.c +++ libvirt-iterator/src/nwfilter/nwfilter_gentech_driver.c @@ -500,14 +500,16 @@ virNWFilterDetermineMissingVarsRec(virNW virNWFilterIncludeDefPtr inc = filter->filterEntries[i]->include; if (rule) { /* check all variables of this rule */ - for (j = 0; j < rule->nvars; j++) { - if (!virHashLookup(vars->hashTable, rule->vars[j])) { + for (j = 0; j < rule->nVarAccess; j++) { + const char *varName; + varName = virNWFilterVarAccessGetVarName(rule->varAccess[j]); + if (!virHashLookup(vars->hashTable, varName)) { val = virNWFilterVarValueCreateSimpleCopyValue("1"); if (!val) { rc = -1; break; } - virNWFilterHashTablePut(missing_vars, rule->vars[j], + virNWFilterHashTablePut(missing_vars, varName, val, 1); } } Index: libvirt-iterator/docs/schemas/nwfilter.rng =================================================================== --- libvirt-iterator.orig/docs/schemas/nwfilter.rng +++ libvirt-iterator/docs/schemas/nwfilter.rng @@ -811,12 +811,15 @@ + + + $[a-zA-Z0-9_]+(\[[ ]*[@]?[0-9]+[ ]*\])? + + + - - - $[a-zA-Z0-9_]+ - + ([a-fA-F0-9]{1,2}:){5}[a-fA-F0-9]{1,2} @@ -826,10 +829,7 @@ - - - $[a-zA-Z0-9_]+ - + ([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9] @@ -839,10 +839,7 @@ - - - $[a-zA-Z0-9_]+ - + ([a-fA-F0-9]{0,4}:){2,7}([a-fA-F0-9]*)(([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9])? @@ -852,10 +849,7 @@ - - - $[a-zA-Z0-9_]+ - + 0 @@ -870,10 +864,7 @@ - - - $[a-zA-Z0-9_]+ - + 0 @@ -892,10 +883,7 @@ 0x([0-3][0-9a-fA-F]|[0-9a-fA-F]) - - - $[a-zA-Z0-9_]+ - + 0 @@ -906,10 +894,7 @@ - - - $[a-zA-Z0-9_]+ - + 0x([6-9a-fA-F][0-9a-fA-F]{2}|[0-9a-fA-F]{4}) @@ -932,10 +917,7 @@ - - - $[a-zA-Z0-9_]+ - + 0x([0-9a-fA-F]{1,3}) @@ -950,10 +932,7 @@ - - - $[a-zA-Z0-9_]+ - + 0x[0-9a-fA-F]{1,2} @@ -968,10 +947,7 @@ - - - $[a-zA-Z0-9_]+ - + 0x[0-9a-fA-F]{1,4} @@ -986,10 +962,7 @@ - - - $[a-zA-Z0-9_]+ - + 0x[0-9a-fA-F]{1,8} @@ -1015,10 +988,7 @@ - - - $[a-zA-Z0-9_]+ - + 0 @@ -1034,10 +1004,7 @@ - - - $[a-zA-Z0-9_]+ - + 0x[0-9a-fA-F]{1,2}