diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c index 2a429757efce054db4930730c1ad6d8e36b01942..c63c807a3395684ac1e015f3f79d3a25e8357e69 100644 --- a/src/conf/nwfilter_params.c +++ b/src/conf/nwfilter_params.c @@ -222,6 +222,210 @@ virNWFilterVarValueAddValue(virNWFilterVarValuePtr val, char *value) return rc; } +void +virNWFilterVarCombIterFree(virNWFilterVarCombIterPtr ci) +{ + unsigned int i; + + if (!ci) + return; + + for (i = 0; i < ci->nIter; i++) + VIR_FREE(ci->iter[i].varNames); + + VIR_FREE(ci); +} + +static int +virNWFilterVarCombIterGetIndexByIterId(virNWFilterVarCombIterPtr ci, + unsigned int iterId) +{ + unsigned int i; + + for (i = 0; i < ci->nIter; i++) + if (ci->iter[i].iterId == iterId) + return i; + + return -1; +} + +static void +virNWFilterVarCombIterEntryInit(virNWFilterVarCombIterEntryPtr cie, + unsigned int iterId) +{ + memset(cie, 0, sizeof(*cie)); + cie->iterId = iterId; +} + +static int +virNWFilterVarCombIterAddVariable(virNWFilterVarCombIterEntryPtr cie, + virNWFilterHashTablePtr hash, + const char *varName) +{ + virNWFilterVarValuePtr varValue; + unsigned int cardinality; + + varValue = virHashLookup(hash->hashTable, varName); + if (varValue == NULL) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find value for variable '%s'"), + varName); + return -1; + } + + cardinality = virNWFilterVarValueGetCardinality(varValue); + + if (cie->nVarNames == 0) { + cie->maxValue = cardinality - 1; + } else { + if (cie->maxValue != cardinality - 1) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Cardinality of list items must be " + "the same for processing them in " + "parallel")); + return -1; + } + } + + if (VIR_EXPAND_N(cie->varNames, cie->nVarNames, 1) < 0) { + virReportOOMError(); + return -1; + } + + cie->varNames[cie->nVarNames - 1] = varName; + + return 0; +} + +/* + * 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, + * meaning it will access $ITEM1[0] and $ITEM2[0] then $ITEM1[1] and $ITEM2[1] + * up to $ITEM1[n] and $ITEM2[n]. For this to work, the cardinality of all + * processed lists must be the same. + * The notation $ITEM1 and $ITEM2 (in one rule) therefore will always have to + * process the items in parallel. This will be an implicit notation for + * $ITEM1[@0] and $ITEM2[@0] to 'lock' the two together. Future notations of + * $ITEM1[@1] and $ITEM2[@2] will make them be processed independently, + * which then would cause all combinations of the items of the two lists to + * be created. + */ +virNWFilterVarCombIterPtr +virNWFilterVarCombIterCreate(virNWFilterHashTablePtr hash, + char * const *vars, unsigned int nVars) +{ + virNWFilterVarCombIterPtr res; + unsigned int i, iterId; + int iterIndex; + + if (VIR_ALLOC_VAR(res, virNWFilterVarCombIterEntry, 1) < 0) { + virReportOOMError(); + return NULL; + } + + res->hashTable = hash; + + /* create the default iterator to support @0 */ + iterId = 0; + + 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; + } + + if (virNWFilterVarCombIterAddVariable(&res->iter[iterIndex], + hash, vars[i]) < 0) + goto err_exit; + } + + return res; + +err_exit: + virNWFilterVarCombIterFree(res); + return NULL; +} + +virNWFilterVarCombIterPtr +virNWFilterVarCombIterNext(virNWFilterVarCombIterPtr ci) +{ + unsigned int i; + + for (i = 0; i < ci->nIter; i++) { + ci->iter[i].curValue++; + if (ci->iter[i].curValue <= ci->iter[i].maxValue) + break; + else + ci->iter[i].curValue = 0; + } + + if (ci->nIter == i) { + virNWFilterVarCombIterFree(ci); + return NULL; + } + + return ci; +} + +const char * +virNWFilterVarCombIterGetVarValue(virNWFilterVarCombIterPtr ci, + const char *varName) +{ + unsigned int i; + bool found = false; + const char *res = NULL; + virNWFilterVarValuePtr value; + unsigned int iterIndex; + + /* currently always accessing iter @0 */ + iterIndex = 0; + + for (i = 0; i < ci->iter[iterIndex].nVarNames; i++) { + if (STREQ(ci->iter[iterIndex].varNames[i], varName)) { + found = true; + break; + } + } + + if (!found) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find variable '%s' in iterator"), + varName); + return NULL; + } + + value = virHashLookup(ci->hashTable->hashTable, varName); + if (!value) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find value for variable '%s'"), + varName); + return NULL; + } + + res = virNWFilterVarValueGetNthValue(value, ci->iter[iterIndex].curValue); + if (!res) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get nth (%u) value of " + "variable '%s'"), + ci->iter[iterIndex].curValue, varName); + return NULL; + } + + return res; +} + static void hashDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) { diff --git a/src/conf/nwfilter_params.h b/src/conf/nwfilter_params.h index ab888649b07a347f500fc894a478ddd5d6135f22..57becc17028f707133394f7717e2cdbbee825933 100644 --- a/src/conf/nwfilter_params.h +++ b/src/conf/nwfilter_params.h @@ -88,4 +88,31 @@ int virNWFilterHashTablePutAll(virNWFilterHashTablePtr src, # define VALID_VARVALUE \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.:" +typedef struct _virNWFilterVarCombIterEntry virNWFilterVarCombIterEntry; +typedef virNWFilterVarCombIterEntry *virNWFilterVarCombIterEntryPtr; +struct _virNWFilterVarCombIterEntry { + unsigned int iterId; + const char **varNames; + size_t nVarNames; + unsigned int maxValue; + unsigned int curValue; +}; + +typedef struct _virNWFilterVarCombIter virNWFilterVarCombIter; +typedef virNWFilterVarCombIter *virNWFilterVarCombIterPtr; +struct _virNWFilterVarCombIter { + virNWFilterHashTablePtr hashTable; + size_t nIter; + virNWFilterVarCombIterEntry iter[0]; +}; +virNWFilterVarCombIterPtr virNWFilterVarCombIterCreate( + virNWFilterHashTablePtr hash, + char * const *vars, unsigned int nVars); + +void virNWFilterVarCombIterFree(virNWFilterVarCombIterPtr ci); +virNWFilterVarCombIterPtr virNWFilterVarCombIterNext( + virNWFilterVarCombIterPtr ci); +const char *virNWFilterVarCombIterGetVarValue(virNWFilterVarCombIterPtr ci, + const char *varname); + #endif /* NWFILTER_PARAMS_H */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 03630dcc31c5195e8a9e1830f58572a0fb2afbae..7906f5dcc6e3ec0c015a06489711e65b9613e3b0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -840,6 +840,10 @@ virNWFilterHashTableFree; virNWFilterHashTablePut; virNWFilterHashTablePutAll; virNWFilterHashTableRemoveEntry; +virNWFilterVarCombIterCreate; +virNWFilterVarCombIterFree; +virNWFilterVarCombIterGetVarValue; +virNWFilterVarCombIterNext; virNWFilterVarValueCreateSimple; virNWFilterVarValueCreateSimpleCopyValue; virNWFilterVarValueGetSimple; diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 7403cbefc170d34398bcf9461228a201ff751232..b7819788c442fe9f41cfed710fc1ceccfd842434 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -208,7 +208,7 @@ static const struct ushort_map l3_protocols[] = { static int -printVar(virNWFilterHashTablePtr vars, +printVar(virNWFilterVarCombIterPtr vars, char *buf, int bufsize, nwItemDescPtr item, int *done) @@ -216,22 +216,11 @@ printVar(virNWFilterHashTablePtr vars, *done = 0; if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) { - virNWFilterVarValuePtr varval; const char *val; - varval = virHashLookup(vars->hashTable, item->var); - if (!varval) { - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot find value for '%s'"), - item->var); - return 1; - } - - val = virNWFilterVarValueGetSimple(varval); + val = virNWFilterVarCombIterGetVarValue(vars, item->var); if (!val) { - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot get simple value of '%s'"), - item->var); + /* error has been reported */ return 1; } @@ -250,7 +239,7 @@ printVar(virNWFilterHashTablePtr vars, static int -_printDataType(virNWFilterHashTablePtr vars, +_printDataType(virNWFilterVarCombIterPtr vars, char *buf, int bufsize, nwItemDescPtr item, bool asHex) @@ -345,7 +334,7 @@ _printDataType(virNWFilterHashTablePtr vars, static int -printDataType(virNWFilterHashTablePtr vars, +printDataType(virNWFilterVarCombIterPtr vars, char *buf, int bufsize, nwItemDescPtr item) { @@ -354,7 +343,7 @@ printDataType(virNWFilterHashTablePtr vars, static int -printDataTypeAsHex(virNWFilterHashTablePtr vars, +printDataTypeAsHex(virNWFilterVarCombIterPtr vars, char *buf, int bufsize, nwItemDescPtr item) { @@ -422,7 +411,7 @@ ebiptablesAddRuleInst(virNWFilterRuleInstPtr res, static int ebtablesHandleEthHdr(virBufferPtr buf, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, ethHdrDataDefPtr ethHdr, bool reverse) { @@ -900,7 +889,7 @@ iptablesInstCommand(virBufferPtr buf, static int iptablesHandleSrcMacAddr(virBufferPtr buf, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, nwItemDescPtr srcMacAddr, int directionIn, bool *srcmacskipped) @@ -937,7 +926,7 @@ err_exit: static int iptablesHandleIpHdr(virBufferPtr buf, virBufferPtr afterStateMatch, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, ipHdrDataDefPtr ipHdr, int directionIn, bool *skipRule, bool *skipMatch, @@ -1111,7 +1100,7 @@ err_exit: static int iptablesHandlePortData(virBufferPtr buf, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, portDataDefPtr portData, int directionIn) { @@ -1217,7 +1206,7 @@ _iptablesCreateRuleInstance(int directionIn, virNWFilterDefPtr nwfilter, virNWFilterRuleDefPtr rule, const char *ifname, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, virNWFilterRuleInstPtr res, const char *match, bool defMatch, const char *accept_target, @@ -1703,7 +1692,7 @@ static int iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter, virNWFilterRuleDefPtr rule, const char *ifname, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, virNWFilterRuleInstPtr res, bool isIPv6) { @@ -1828,7 +1817,7 @@ static int iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter, virNWFilterRuleDefPtr rule, const char *ifname, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, virNWFilterRuleInstPtr res, bool isIPv6) { @@ -1953,7 +1942,7 @@ ebtablesCreateRuleInstance(char chainPrefix, virNWFilterDefPtr nwfilter, virNWFilterRuleDefPtr rule, const char *ifname, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, virNWFilterRuleInstPtr res, bool reverse) { @@ -2445,7 +2434,7 @@ ebiptablesCreateRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED, virNWFilterDefPtr nwfilter, virNWFilterRuleDefPtr rule, const char *ifname, - virNWFilterHashTablePtr vars, + virNWFilterVarCombIterPtr vars, virNWFilterRuleInstPtr res) { int rc = 0; @@ -2529,6 +2518,44 @@ ebiptablesCreateRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED, return rc; } +static int +ebiptablesCreateRuleInstanceIterate( + virConnectPtr conn ATTRIBUTE_UNUSED, + enum virDomainNetType nettype ATTRIBUTE_UNUSED, + virNWFilterDefPtr nwfilter, + virNWFilterRuleDefPtr rule, + const char *ifname, + virNWFilterHashTablePtr vars, + virNWFilterRuleInstPtr res) +{ + int rc = 0; + virNWFilterVarCombIterPtr vciter; + + /* 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. + */ + vciter = virNWFilterVarCombIterCreate(vars, rule->vars, rule->nvars); + if (!vciter) + return 1; + + do { + rc = ebiptablesCreateRuleInstance(conn, + nettype, + nwfilter, + rule, + ifname, + vciter, + res); + if (rc) + break; + vciter = virNWFilterVarCombIterNext(vciter); + } while (vciter != NULL); + + virNWFilterVarCombIterFree(vciter); + + return rc; +} static int ebiptablesFreeRuleInstance(void *_inst) @@ -3796,7 +3823,7 @@ virNWFilterTechDriver ebiptables_driver = { .init = ebiptablesDriverInit, .shutdown = ebiptablesDriverShutdown, - .createRuleInstance = ebiptablesCreateRuleInstance, + .createRuleInstance = ebiptablesCreateRuleInstanceIterate, .applyNewRules = ebiptablesApplyNewRules, .tearNewRules = ebiptablesTearNewRules, .tearOldRules = ebiptablesTearOldRules,