[libvirt] [PATCH v2 0/6] nwfilter: Enable access to variables via iterator or index

This patch enables access to variables in filters using indep. iterators ($TEST[$@2]) or via index ($TEST[1]). Three test cases are added that are also being used for libvirt-TCK to check that the instantiation of the filtering rules is correct. v1 -> v2: - addressed Eric Blake's comments Regards, Stefan

In this patch we introduce testing whether the iterator points to a unique set of entries that have not been seen before at one of the previous iterations. The point is to eliminate duplicates and with that unnecessary filtering rules by preventing identical filtering rules from being instantiated. Example with two lists: list1 = [1,2,1] list2 = [1,3,1] The 1st iteration would take the 1st items of each list -> 1,1 The 2nd iteration would take the 2nd items of each list -> 2,3 The 3rd iteration would take the 3rd items of each list -> 1,1 but skip them since this same pair has already been encountered in the 1st iteration Implementation-wise this is solved by taking the n-th element of list1 and comparing it against elements 1..n-1. If no equivalent is found, then there is no possibility of this being a duplicate. In case an equivalent element is found at position i, then the n-th element in the 2nd list is compared against the i-th element in the 2nd list and if that is not the same, then this is a unique pair, otherwise it is not unique and we may need to do the same comparison on the 3rd list. --- src/conf/nwfilter_params.c | 55 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) Index: libvirt-iterator/src/conf/nwfilter_params.c =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.c +++ libvirt-iterator/src/conf/nwfilter_params.c @@ -348,6 +348,52 @@ virNWFilterVarCombIterAddVariable(virNWF } /* + * Test whether the iterator entry points to a distinguished set of entries + * that have not been seen before at one of the previous iterations. + * + * The point of this function is to eliminate duplicates. + * Example with two lists: + * + * list1 = [1,2,1] + * list2 = [1,3,1] + * + * The 1st iteration would take the 1st items of each list -> 1,1 + * The 2nd iteration would take the 2nd items of each list -> 2,3 + * The 3rd iteration would take the 3rd items of each list -> 1,1 but + * skip them since this pair has already been encountered in the 1st iteration + */ +static bool +virNWFilterVarCombIterEntryAreUniqueEntries(virNWFilterVarCombIterEntryPtr cie, + virNWFilterHashTablePtr hash) +{ + unsigned int i, j; + virNWFilterVarValuePtr varValue, tmp; + const char *value; + + varValue = virHashLookup(hash->hashTable, cie->varNames[0]); + + value = virNWFilterVarValueGetNthValue(varValue, cie->curValue); + + for (i = 0; i < cie->curValue; i++) { + if (STREQ(value, virNWFilterVarValueGetNthValue(varValue, i))) { + bool isSame = true; + for (j = 1; j < cie->nVarNames; j++) { + tmp = virHashLookup(hash->hashTable, cie->varNames[j]); + if (!STREQ(virNWFilterVarValueGetNthValue(tmp, cie->curValue), + virNWFilterVarValueGetNthValue(tmp, i))) { + isSame = false; + break; + } + } + if (isSame) + return false; + } + } + + return true; +} + +/* * Create an iterator over the contents of the given variables. All variables * must have entries in the hash table. * The iterator that is created processes all given variables in parallel, @@ -414,11 +460,16 @@ virNWFilterVarCombIterNext(virNWFilterVa unsigned int i; for (i = 0; i < ci->nIter; i++) { +next: ci->iter[i].curValue++; - if (ci->iter[i].curValue <= ci->iter[i].maxValue) + if (ci->iter[i].curValue <= ci->iter[i].maxValue) { + if (!virNWFilterVarCombIterEntryAreUniqueEntries( + &ci->iter[i], ci->hashTable)) + goto next; break; - else + } else { ci->iter[i].curValue = 0; + } } if (ci->nIter == i) {

This patch introduces the capability to use a different iterator per variable. The currently supported notation of variables in a filtering rule like <rule action='accept' direction='out'> <tcp srcipaddr='$A' srcportstart='$B'/> </rule> 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 <rule action='accept' direction='out'> <tcp srcipaddr='$A[@1]' srcportstart='$B[@2]'/> </rule> 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 <rule action='accept' direction='out'> <tcp srcipaddr='$A[@0]' srcportstart='$B[@0]'/> </rule> --- 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[@<number>] -> iterator */ + dest->accessType = VIR_NWFILTER_VAR_ACCESS_ITERATOR; + input++; + } else { + /* in the form 'IP[<number>] -> element */ + dest->accessType = VIR_NWFILTER_VAR_ACCESS_ELEMENT; + /* not supported (yet) */ + virNWFilterReportError(VIR_ERR_INVALID_ARG, + _("Variable access in the form " + "var[<index>] 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 @@ </choice> </define> + <define name="variable-name-type"> + <data type="string"> + <param name="pattern">$[a-zA-Z0-9_]+(\[[ ]*[@]?[0-9]+[ ]*\])?</param> + </data> + </define> + <define name="addrMAC"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">([a-fA-F0-9]{1,2}:){5}[a-fA-F0-9]{1,2}</param> @@ -826,10 +829,7 @@ <define name="addrIP"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">([0-2]?[0-9]?[0-9]\.){3}[0-2]?[0-9]?[0-9]</param> @@ -839,10 +839,7 @@ <define name="addrIPv6"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">([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])?</param> @@ -852,10 +849,7 @@ <define name="addrMask"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="int"> <param name="minInclusive">0</param> @@ -870,10 +864,7 @@ <define name="addrMaskv6"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="int"> <param name="minInclusive">0</param> @@ -892,10 +883,7 @@ <param name="pattern">0x([0-3][0-9a-fA-F]|[0-9a-fA-F])</param> </data> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="int"> <param name="minInclusive">0</param> @@ -906,10 +894,7 @@ <define name="mac-protocolid"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">0x([6-9a-fA-F][0-9a-fA-F]{2}|[0-9a-fA-F]{4})</param> @@ -932,10 +917,7 @@ <define name="vlan-vlanid"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">0x([0-9a-fA-F]{1,3})</param> @@ -950,10 +932,7 @@ <define name="uint8range"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">0x[0-9a-fA-F]{1,2}</param> @@ -968,10 +947,7 @@ <define name="uint16range"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">0x[0-9a-fA-F]{1,4}</param> @@ -986,10 +962,7 @@ <define name="uint32range"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">0x[0-9a-fA-F]{1,8}</param> @@ -1015,10 +988,7 @@ <define name="arpOpcodeType"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="int"> <param name="minInclusive">0</param> @@ -1034,10 +1004,7 @@ <define name="ipProtocolType"> <choice> - <!-- variable --> - <data type="string"> - <param name="pattern">$[a-zA-Z0-9_]+</param> - </data> + <ref name="variable-name-type"/> <data type="string"> <param name="pattern">0x[0-9a-fA-F]{1,2}</param>

This patch adds access to single elements of variables via index. Example: <rule action='accept' direction='in' priority='500'> <tcp srcipaddr='$ADDR[1]' srcportstart='$B[2]'/> </rule> --- src/conf/nwfilter_params.c | 82 +++++++++++++++++++++++++++++++++++---------- src/conf/nwfilter_params.h | 9 +++- 2 files changed, 71 insertions(+), 20 deletions(-) Index: libvirt-iterator/src/conf/nwfilter_params.c =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.c +++ libvirt-iterator/src/conf/nwfilter_params.c @@ -35,7 +35,10 @@ #define VIR_FROM_THIS VIR_FROM_NWFILTER static bool isValidVarValue(const char *value); - +static void virNWFilterVarAccessSetIntIterId(virNWFilterVarAccessPtr, + unsigned int); +static unsigned int virNWFilterVarAccessGetIntIterId( + const virNWFilterVarAccessPtr); void virNWFilterVarValueFree(virNWFilterVarValuePtr val) @@ -313,7 +316,7 @@ virNWFilterVarCombIterAddVariable(virNWF const virNWFilterVarAccessPtr varAccess) { virNWFilterVarValuePtr varValue; - unsigned int cardinality; + unsigned int maxValue, minValue; const char *varName = virNWFilterVarAccessGetVarName(varAccess); varValue = virHashLookup(hash->hashTable, varName); @@ -324,12 +327,25 @@ virNWFilterVarCombIterAddVariable(virNWF return -1; } - cardinality = virNWFilterVarValueGetCardinality(varValue); + switch (virNWFilterVarAccessGetType(varAccess)) { + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + maxValue = virNWFilterVarAccessGetIndex(varAccess); + minValue = maxValue; + break; + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + maxValue = virNWFilterVarValueGetCardinality(varValue) - 1; + minValue = 0; + break; + case VIR_NWFILTER_VAR_ACCESS_LAST: + return -1; + } if (cie->nVarNames == 0) { - cie->maxValue = cardinality - 1; + cie->maxValue = maxValue; + cie->minValue = minValue; + cie->curValue = minValue; } else { - if (cie->maxValue != cardinality - 1) { + if (cie->maxValue != maxValue) { virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, _("Cardinality of list items must be " "the same for processing them in " @@ -410,12 +426,13 @@ virNWFilterVarCombIterEntryAreUniqueEntr */ virNWFilterVarCombIterPtr virNWFilterVarCombIterCreate(virNWFilterHashTablePtr hash, - const virNWFilterVarAccessPtr *varAccess, + virNWFilterVarAccessPtr *varAccess, size_t nVarAccess) { virNWFilterVarCombIterPtr res; unsigned int i, iterId; int iterIndex = -1; + unsigned int nextIntIterId = VIR_NWFILTER_MAX_ITERID + 1; if (VIR_ALLOC_VAR(res, virNWFilterVarCombIterEntry, 1 + nVarAccess) < 0) { virReportOOMError(); @@ -442,6 +459,13 @@ virNWFilterVarCombIterCreate(virNWFilter } break; case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + iterIndex = res->nIter; + virNWFilterVarAccessSetIntIterId(varAccess[i], nextIntIterId); + virNWFilterVarCombIterEntryInit(&res->iter[iterIndex], + nextIntIterId); + nextIntIterId++; + res->nIter++; + break; case VIR_NWFILTER_VAR_ACCESS_LAST: break; } @@ -472,7 +496,7 @@ next: goto next; break; } else { - ci->iter[i].curValue = 0; + ci->iter[i].curValue = ci->iter[i].minValue; } } @@ -507,9 +531,15 @@ virNWFilterVarCombIterGetVarValue(virNWF } break; case VIR_NWFILTER_VAR_ACCESS_ELEMENT: - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, - _("Element access via index is not possible")); - return NULL; + iterId = virNWFilterVarAccessGetIntIterId(vap); + iterIndex = virNWFilterVarCombIterGetIndexByIterId(ci, iterId); + if (iterIndex < 0) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get iterator index for " + "(internal) iterator ID %u"), iterId); + return NULL; + } + break; case VIR_NWFILTER_VAR_ACCESS_LAST: return NULL; } @@ -874,7 +904,8 @@ virNWFilterVarAccessEqual(const virNWFil switch (a->accessType) { case VIR_NWFILTER_VAR_ACCESS_ELEMENT: - return (a->u.index == b->u.index); + return (a->u.index.index == b->u.index.index && + a->u.index.intIterId == b->u.index.intIterId); break; case VIR_NWFILTER_VAR_ACCESS_ITERATOR: return (a->u.iterId == b->u.iterId); @@ -938,11 +969,6 @@ virNWFilterVarAccessParse(const char *va } else { /* in the form 'IP[<number>] -> element */ dest->accessType = VIR_NWFILTER_VAR_ACCESS_ELEMENT; - /* not supported (yet) */ - virNWFilterReportError(VIR_ERR_INVALID_ARG, - _("Variable access in the form " - "var[<index>] is not supported")); - goto err_exit; } if (virStrToLong_ui(input, &end_ptr, 10, &result) < 0) @@ -965,7 +991,8 @@ virNWFilterVarAccessParse(const char *va switch (dest->accessType) { case VIR_NWFILTER_VAR_ACCESS_ELEMENT: - dest->u.index = result; + dest->u.index.index = result; + dest->u.index.intIterId = ~0; break; case VIR_NWFILTER_VAR_ACCESS_ITERATOR: if (result > VIR_NWFILTER_MAX_ITERID) { @@ -998,7 +1025,7 @@ virNWFilterVarAccessPrint(virNWFilterVar virBufferAdd(buf, vap->varName, -1); switch (vap->accessType) { case VIR_NWFILTER_VAR_ACCESS_ELEMENT: - virBufferAsprintf(buf, "[%u]", vap->u.index); + virBufferAsprintf(buf, "[%u]", vap->u.index.index); break; case VIR_NWFILTER_VAR_ACCESS_ITERATOR: if (vap->u.iterId != 0) @@ -1026,3 +1053,22 @@ virNWFilterVarAccessGetIterId(const virN { return vap->u.iterId; } + +unsigned int +virNWFilterVarAccessGetIndex(const virNWFilterVarAccessPtr vap) +{ + return vap->u.index.index; +} + +static void +virNWFilterVarAccessSetIntIterId(virNWFilterVarAccessPtr vap, + unsigned int intIterId) +{ + vap->u.index.intIterId = intIterId; +} + +static unsigned int +virNWFilterVarAccessGetIntIterId(const virNWFilterVarAccessPtr vap) +{ + return vap->u.index.intIterId; +} Index: libvirt-iterator/src/conf/nwfilter_params.h =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.h +++ libvirt-iterator/src/conf/nwfilter_params.h @@ -103,7 +103,10 @@ typedef virNWFilterVarAccess *virNWFilte struct _virNWFilterVarAccess { enum virNWFilterVarAccessType accessType; union { - unsigned int index; + struct { + unsigned int index; + unsigned int intIterId; + } index; unsigned int iterId; } u; char *varName; @@ -121,6 +124,7 @@ const char *virNWFilterVarAccessGetVarNa enum virNWFilterVarAccessType virNWFilterVarAccessGetType( const virNWFilterVarAccessPtr vap); unsigned int virNWFilterVarAccessGetIterId(const virNWFilterVarAccessPtr vap); +unsigned int virNWFilterVarAccessGetIndex(const virNWFilterVarAccessPtr vap); typedef struct _virNWFilterVarCombIterEntry virNWFilterVarCombIterEntry; @@ -131,6 +135,7 @@ struct _virNWFilterVarCombIterEntry { size_t nVarNames; unsigned int maxValue; unsigned int curValue; + unsigned int minValue; }; typedef struct _virNWFilterVarCombIter virNWFilterVarCombIter; @@ -142,7 +147,7 @@ struct _virNWFilterVarCombIter { }; virNWFilterVarCombIterPtr virNWFilterVarCombIterCreate( virNWFilterHashTablePtr hash, - const virNWFilterVarAccessPtr *vars, + virNWFilterVarAccessPtr *vars, size_t nVars); void virNWFilterVarCombIterFree(virNWFilterVarCombIterPtr ci);

Address side effect of accessing a variable via an index: Filters accessing a variable where an element is accessed that is beyond the size of the list (for example $TEST[10] and only 2 elements are available) cannot instantiate that filter. Test for this and report proper error to user. --- src/conf/nwfilter_params.c | 29 +++++++++++++++++++++++++++++ src/conf/nwfilter_params.h | 3 ++- src/libvirt_private.syms | 2 ++ src/nwfilter/nwfilter_gentech_driver.c | 23 ++++++++++++++++++----- 4 files changed, 51 insertions(+), 6 deletions(-) Index: libvirt-iterator/src/conf/nwfilter_params.h =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.h +++ libvirt-iterator/src/conf/nwfilter_params.h @@ -125,7 +125,8 @@ enum virNWFilterVarAccessType virNWFilte const virNWFilterVarAccessPtr vap); unsigned int virNWFilterVarAccessGetIterId(const virNWFilterVarAccessPtr vap); unsigned int virNWFilterVarAccessGetIndex(const virNWFilterVarAccessPtr vap); - +bool virNWFilterVarAccessIsAvailable(const virNWFilterVarAccessPtr vap, + const virNWFilterHashTablePtr hash); typedef struct _virNWFilterVarCombIterEntry virNWFilterVarCombIterEntry; typedef virNWFilterVarCombIterEntry *virNWFilterVarCombIterEntryPtr; 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 @@ -501,16 +501,29 @@ virNWFilterDetermineMissingVarsRec(virNW if (rule) { /* check all variables of this rule */ for (j = 0; j < rule->nVarAccess; j++) { - const char *varName; - varName = virNWFilterVarAccessGetVarName(rule->varAccess[j]); - if (!virHashLookup(vars->hashTable, varName)) { + if (!virNWFilterVarAccessIsAvailable(rule->varAccess[j], + vars)) { + const char *varAccess; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virNWFilterVarAccessPrint(rule->varAccess[j], &buf); + if (virBufferError(&buf)) { + virReportOOMError(); + rc = -1; + break; + } + val = virNWFilterVarValueCreateSimpleCopyValue("1"); if (!val) { + virBufferFreeAndReset(&buf); rc = -1; break; } - virNWFilterHashTablePut(missing_vars, varName, + + varAccess = virBufferContentAndReset(&buf); + virNWFilterHashTablePut(missing_vars, varAccess, val, 1); + VIR_FREE(varAccess); } } if (rc) @@ -752,7 +765,7 @@ err_unresolvable_vars: if (buf) { virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, _("Cannot instantiate filter due to unresolvable " - "variables: %s"), buf); + "variables or unavailable list elements: %s"), buf); VIR_FREE(buf); } Index: libvirt-iterator/src/conf/nwfilter_params.c =================================================================== --- libvirt-iterator.orig/src/conf/nwfilter_params.c +++ libvirt-iterator/src/conf/nwfilter_params.c @@ -1072,3 +1072,32 @@ virNWFilterVarAccessGetIntIterId(const v { return vap->u.index.intIterId; } + +bool +virNWFilterVarAccessIsAvailable(const virNWFilterVarAccessPtr varAccess, + const virNWFilterHashTablePtr hash) +{ + const char *varName = virNWFilterVarAccessGetVarName(varAccess); + const char *res; + unsigned int idx; + virNWFilterVarValuePtr varValue; + + varValue = virHashLookup(hash->hashTable, varName); + if (!varValue) + return false; + + switch (virNWFilterVarAccessGetType(varAccess)) { + case VIR_NWFILTER_VAR_ACCESS_ELEMENT: + idx = virNWFilterVarAccessGetIndex(varAccess); + res = virNWFilterVarValueGetNthValue(varValue, idx); + if (res == NULL) + return false; + break; + case VIR_NWFILTER_VAR_ACCESS_ITERATOR: + break; + case VIR_NWFILTER_VAR_ACCESS_LAST: + return false; + } + + return true; +} Index: libvirt-iterator/src/libvirt_private.syms =================================================================== --- libvirt-iterator.orig/src/libvirt_private.syms +++ libvirt-iterator/src/libvirt_private.syms @@ -833,6 +833,8 @@ virNWFilterHashTablePut; virNWFilterHashTablePutAll; virNWFilterHashTableRemoveEntry; virNWFilterVarAccessGetVarName; +virNWFilterVarAccessIsAvailable; +virNWFilterVarAccessPrint; virNWFilterVarCombIterCreate; virNWFilterVarCombIterFree; virNWFilterVarCombIterGetVarValue;

This patch adds a couple of XML parser / schema validator test cases for the new 'ways' to access variables via index or iterator. --- tests/nwfilterxml2xmlin/iter-test1.xml | 6 ++++++ tests/nwfilterxml2xmlin/iter-test2.xml | 23 +++++++++++++++++++++++ tests/nwfilterxml2xmlin/iter-test3.xml | 13 +++++++++++++ tests/nwfilterxml2xmlout/iter-test1.xml | 6 ++++++ tests/nwfilterxml2xmlout/iter-test2.xml | 21 +++++++++++++++++++++ tests/nwfilterxml2xmlout/iter-test3.xml | 12 ++++++++++++ tests/nwfilterxml2xmltest.c | 3 +++ 7 files changed, 84 insertions(+) Index: libvirt-iterator/tests/nwfilterxml2xmlin/iter-test1.xml =================================================================== --- /dev/null +++ libvirt-iterator/tests/nwfilterxml2xmlin/iter-test1.xml @@ -0,0 +1,6 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out'> + <tcp srcipaddr='$A' srcportstart='$B' dscp='2'/> + </rule> +</filter> Index: libvirt-iterator/tests/nwfilterxml2xmlin/iter-test2.xml =================================================================== --- /dev/null +++ libvirt-iterator/tests/nwfilterxml2xmlin/iter-test2.xml @@ -0,0 +1,23 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out'> + <tcp srcipaddr='$A' srcportstart='$B[@0]' dscp='1'/> + </rule> + <rule action='accept' direction='out'> + <udp srcipaddr='$A[@1]' srcportstart='$B[@2]' dscp='2'/> + </rule> + <rule action='accept' direction='out'> + <sctp srcipaddr='$A[@1]' srcportstart='$B[@2]' dstportstart='$C[@2]' + dscp='3'/> + </rule> + <rule action='accept' direction='out'> + <tcp srcipaddr='$A[@1]' srcportstart='$B[@2]' dstportstart='$C[@3]' + dscp='4'/> + </rule> + <rule action='accept' direction='out'> + <udp srcipaddr='$A[@1]' dstipaddr='$A[@2]' dscp='5'/> + </rule> + <rule action='accept' direction='out'> + <sctp srcipaddr='$A' dstipaddr='$A' dscp='6'/> + </rule> +</filter> Index: libvirt-iterator/tests/nwfilterxml2xmlin/iter-test3.xml =================================================================== --- /dev/null +++ libvirt-iterator/tests/nwfilterxml2xmlin/iter-test3.xml @@ -0,0 +1,13 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out'> + <tcp srcipaddr='$A[ 0]' srcportstart='$B[ @0 ] ' dscp='1'/> + </rule> + <rule action='accept' direction='out'> + <udp srcipaddr='$A[1 ]' srcportstart='$B[ @2 ]' dscp='2'/> + </rule> + <rule action='accept' direction='out'> + <sctp srcipaddr='$A[ 1 ] ' srcportstart='$B[2 ] ' dstportstart='$C[ 2 ]' + dscp='3'/> + </rule> +</filter> Index: libvirt-iterator/tests/nwfilterxml2xmlout/iter-test1.xml =================================================================== --- /dev/null +++ libvirt-iterator/tests/nwfilterxml2xmlout/iter-test1.xml @@ -0,0 +1,6 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out' priority='500'> + <tcp srcipaddr='$A' dscp='2' srcportstart='$B'/> + </rule> +</filter> Index: libvirt-iterator/tests/nwfilterxml2xmlout/iter-test2.xml =================================================================== --- /dev/null +++ libvirt-iterator/tests/nwfilterxml2xmlout/iter-test2.xml @@ -0,0 +1,21 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out' priority='500'> + <tcp srcipaddr='$A' dscp='1' srcportstart='$B'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <udp srcipaddr='$A[@1]' dscp='2' srcportstart='$B[@2]'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <sctp srcipaddr='$A[@1]' dscp='3' srcportstart='$B[@2]' dstportstart='$C[@2]'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <tcp srcipaddr='$A[@1]' dscp='4' srcportstart='$B[@2]' dstportstart='$C[@3]'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <udp srcipaddr='$A[@1]' dstipaddr='$A[@2]' dscp='5'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <sctp srcipaddr='$A' dstipaddr='$A' dscp='6'/> + </rule> +</filter> Index: libvirt-iterator/tests/nwfilterxml2xmlout/iter-test3.xml =================================================================== --- /dev/null +++ libvirt-iterator/tests/nwfilterxml2xmlout/iter-test3.xml @@ -0,0 +1,12 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out' priority='500'> + <tcp srcipaddr='$A[0]' dscp='1' srcportstart='$B'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <udp srcipaddr='$A[1]' dscp='2' srcportstart='$B[@2]'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <sctp srcipaddr='$A[1]' dscp='3' srcportstart='$B[2]' dstportstart='$C[2]'/> + </rule> +</filter> Index: libvirt-iterator/tests/nwfilterxml2xmltest.c =================================================================== --- libvirt-iterator.orig/tests/nwfilterxml2xmltest.c +++ libvirt-iterator/tests/nwfilterxml2xmltest.c @@ -153,6 +153,9 @@ mymain(void) DO_TEST("chain_prefixtest1", true); /* derived from arp-test */ DO_TEST("attr-value-test", false); + DO_TEST("iter-test1", false); + DO_TEST("iter-test2", false); + DO_TEST("iter-test3", false); return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); }

This patch adds documentation about the new 'ways' that users can access the contents of variables in filters: - access via index: $TEST[2] - access via iterators $TEST[@1] --- docs/formatnwfilter.html.in | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) Index: libvirt-iterator/docs/formatnwfilter.html.in =================================================================== --- libvirt-iterator.orig/docs/formatnwfilter.html.in +++ libvirt-iterator/docs/formatnwfilter.html.in @@ -308,7 +308,69 @@ </rule> ... </pre> + <p> + <span class="since">Since 0.9.10</span> it is possible to access + individual elements of a variable holding a list of elements. + A filtering rule like the following accesses the 2nd element + of the variable DSTPORTS. + </p> +<pre> + ... + <rule action='accept' direction='in' priority='500'> + <udp dstportstart='$DSTPORTS[1]'/> + </rule> + ... +</pre> + <p> + <span class="since">Since 0.9.10</span> it is possible to create + filtering rules that instantiate all combinations of rules from + different lists using the notation of + <code>$VARIABLE[@<iterator ID>]</code>. + The following rule allows a virtual machine to + receive traffic on a set of ports, which are specified in DSTPORTS, + from the set of source IP address specified in SRCIPADDRESSES. + The rule generates all combinations of elements of the variable + DSTPORT with those of SRCIPADDRESSES by using two independent + iterators to access their elements. + </p> +<pre> + ... + <rule action='accept' direction='in' priority='500'> + <ip srcipaddr='$SRCIPADDRESSES[@1]' dstportstart='$DSTPORTS[@2]'/> + </rule> + ... +</pre> + <p> + In an example we assign concrete values to SRCIPADDRESSES and DSTPORTS + </p> +<pre> + SRCIPADDRESSES = [ 10.0.0.1, 11.1.2.3 ] + DSTPORTS = [ 80, 8080 ] +</pre> + <p> + Accessing the variables using $SRCIPADDRESSES[@1] and $DSTPORTS[@2] + would then result in all combinations of addresses and ports being created: + </p> +<pre> + 10.0.0.1, 80 + 10.0.0.1, 8080 + 11.1.2.3, 80 + 11.1.2.3, 8080 +</pre> + <p> + Accessing the same variables using a single iterator, for example by using the + the notation $SRCIPADDRESSES[@1] and $DSTPORTS[@1], would result in the parallel + access to both lists and result in the following combinations: + </p> +<pre> + 10.0.0.1, 80 + 11.1.2.3, 8080 +</pre> + <p> + Further, the notation of $VARIABLE is short-hand for $VARIABLE[@0]. The former + notation always assumes the iterator with Id '0'. + <p> <h2><a name="nwfelems">Element and attribute overview</a></h2> <p>

On 01/10/2012 02:04 PM, Stefan Berger wrote:
This patch adds documentation about the new 'ways' that users can access the contents of variables in filters:
- access via index: $TEST[2] - access via iterators $TEST[@1]
+ <p> + Accessing the same variables using a single iterator, for example by using the + the notation $SRCIPADDRESSES[@1] and $DSTPORTS[@1], would result in the parallel
'make syntax-check' griped about the doubled "the" across line boundary. Fix that before pushing (and maybe reformat these lines to fit 80 columns while you are at it). But that's minor, so no need for posting a v3. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 01/10/2012 02:04 PM, Stefan Berger wrote:
This patch enables access to variables in filters using indep. iterators ($TEST[$@2]) or via index ($TEST[1]).
Three test cases are added that are also being used for libvirt-TCK to check that the instantiation of the filtering rules is correct.
v1 -> v2: - addressed Eric Blake's comments
ACK series; I looked through all the patches, as well as compile-tested, and things seemed just fine now, except for one nit in patch 6/6. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 01/10/2012 05:51 PM, Eric Blake wrote:
On 01/10/2012 02:04 PM, Stefan Berger wrote:
This patch enables access to variables in filters using indep. iterators ($TEST[$@2]) or via index ($TEST[1]).
Three test cases are added that are also being used for libvirt-TCK to check that the instantiation of the filtering rules is correct.
v1 -> v2: - addressed Eric Blake's comments ACK series; I looked through all the patches, as well as compile-tested, and things seemed just fine now, except for one nit in patch 6/6.
Pushed the series with nit fixed. Stefan
participants (2)
-
Eric Blake
-
Stefan Berger