Create rules for each member of a list

This patch extends the NWFilter driver for Linux (ebiptables) to create
rules for each member of a previously introduced list. If for example
an attribute value (internally) looks like this:

IP = [10.0.0.1, 10.0.0.2, 10.0.0.3]

then 3 rules will be generated for a rule accessing the variable 'IP',
one for each member of the list. The effect of this is that this now
allows for filtering for multiple values in one field. This can then be
used to support for filtering/allowing of multiple IP addresses per
interface.

An iterator is introduced that extracts each member of a list and
puts it into a hash table which then is passed to the function creating
a rule. For the above example the iterator would cause 3 loops.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2011-11-18 11:58:18 -05:00 committed by Stefan Berger
parent 581d1cea34
commit c80296e21a
4 changed files with 289 additions and 27 deletions

View File

@ -222,6 +222,210 @@ virNWFilterVarValueAddValue(virNWFilterVarValuePtr val, char *value)
return rc; 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 static void
hashDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) hashDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
{ {

View File

@ -88,4 +88,31 @@ int virNWFilterHashTablePutAll(virNWFilterHashTablePtr src,
# define VALID_VARVALUE \ # define VALID_VARVALUE \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.:" "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 */ #endif /* NWFILTER_PARAMS_H */

View File

@ -840,6 +840,10 @@ virNWFilterHashTableFree;
virNWFilterHashTablePut; virNWFilterHashTablePut;
virNWFilterHashTablePutAll; virNWFilterHashTablePutAll;
virNWFilterHashTableRemoveEntry; virNWFilterHashTableRemoveEntry;
virNWFilterVarCombIterCreate;
virNWFilterVarCombIterFree;
virNWFilterVarCombIterGetVarValue;
virNWFilterVarCombIterNext;
virNWFilterVarValueCreateSimple; virNWFilterVarValueCreateSimple;
virNWFilterVarValueCreateSimpleCopyValue; virNWFilterVarValueCreateSimpleCopyValue;
virNWFilterVarValueGetSimple; virNWFilterVarValueGetSimple;

View File

@ -208,7 +208,7 @@ static const struct ushort_map l3_protocols[] = {
static int static int
printVar(virNWFilterHashTablePtr vars, printVar(virNWFilterVarCombIterPtr vars,
char *buf, int bufsize, char *buf, int bufsize,
nwItemDescPtr item, nwItemDescPtr item,
int *done) int *done)
@ -216,22 +216,11 @@ printVar(virNWFilterHashTablePtr vars,
*done = 0; *done = 0;
if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) { if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
virNWFilterVarValuePtr varval;
const char *val; const char *val;
varval = virHashLookup(vars->hashTable, item->var); val = virNWFilterVarCombIterGetVarValue(vars, item->var);
if (!varval) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find value for '%s'"),
item->var);
return 1;
}
val = virNWFilterVarValueGetSimple(varval);
if (!val) { if (!val) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, /* error has been reported */
_("cannot get simple value of '%s'"),
item->var);
return 1; return 1;
} }
@ -250,7 +239,7 @@ printVar(virNWFilterHashTablePtr vars,
static int static int
_printDataType(virNWFilterHashTablePtr vars, _printDataType(virNWFilterVarCombIterPtr vars,
char *buf, int bufsize, char *buf, int bufsize,
nwItemDescPtr item, nwItemDescPtr item,
bool asHex) bool asHex)
@ -345,7 +334,7 @@ _printDataType(virNWFilterHashTablePtr vars,
static int static int
printDataType(virNWFilterHashTablePtr vars, printDataType(virNWFilterVarCombIterPtr vars,
char *buf, int bufsize, char *buf, int bufsize,
nwItemDescPtr item) nwItemDescPtr item)
{ {
@ -354,7 +343,7 @@ printDataType(virNWFilterHashTablePtr vars,
static int static int
printDataTypeAsHex(virNWFilterHashTablePtr vars, printDataTypeAsHex(virNWFilterVarCombIterPtr vars,
char *buf, int bufsize, char *buf, int bufsize,
nwItemDescPtr item) nwItemDescPtr item)
{ {
@ -422,7 +411,7 @@ ebiptablesAddRuleInst(virNWFilterRuleInstPtr res,
static int static int
ebtablesHandleEthHdr(virBufferPtr buf, ebtablesHandleEthHdr(virBufferPtr buf,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
ethHdrDataDefPtr ethHdr, ethHdrDataDefPtr ethHdr,
bool reverse) bool reverse)
{ {
@ -900,7 +889,7 @@ iptablesInstCommand(virBufferPtr buf,
static int static int
iptablesHandleSrcMacAddr(virBufferPtr buf, iptablesHandleSrcMacAddr(virBufferPtr buf,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
nwItemDescPtr srcMacAddr, nwItemDescPtr srcMacAddr,
int directionIn, int directionIn,
bool *srcmacskipped) bool *srcmacskipped)
@ -937,7 +926,7 @@ err_exit:
static int static int
iptablesHandleIpHdr(virBufferPtr buf, iptablesHandleIpHdr(virBufferPtr buf,
virBufferPtr afterStateMatch, virBufferPtr afterStateMatch,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
ipHdrDataDefPtr ipHdr, ipHdrDataDefPtr ipHdr,
int directionIn, int directionIn,
bool *skipRule, bool *skipMatch, bool *skipRule, bool *skipMatch,
@ -1111,7 +1100,7 @@ err_exit:
static int static int
iptablesHandlePortData(virBufferPtr buf, iptablesHandlePortData(virBufferPtr buf,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
portDataDefPtr portData, portDataDefPtr portData,
int directionIn) int directionIn)
{ {
@ -1217,7 +1206,7 @@ _iptablesCreateRuleInstance(int directionIn,
virNWFilterDefPtr nwfilter, virNWFilterDefPtr nwfilter,
virNWFilterRuleDefPtr rule, virNWFilterRuleDefPtr rule,
const char *ifname, const char *ifname,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
virNWFilterRuleInstPtr res, virNWFilterRuleInstPtr res,
const char *match, bool defMatch, const char *match, bool defMatch,
const char *accept_target, const char *accept_target,
@ -1703,7 +1692,7 @@ static int
iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter, iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter,
virNWFilterRuleDefPtr rule, virNWFilterRuleDefPtr rule,
const char *ifname, const char *ifname,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
virNWFilterRuleInstPtr res, virNWFilterRuleInstPtr res,
bool isIPv6) bool isIPv6)
{ {
@ -1828,7 +1817,7 @@ static int
iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter, iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
virNWFilterRuleDefPtr rule, virNWFilterRuleDefPtr rule,
const char *ifname, const char *ifname,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
virNWFilterRuleInstPtr res, virNWFilterRuleInstPtr res,
bool isIPv6) bool isIPv6)
{ {
@ -1953,7 +1942,7 @@ ebtablesCreateRuleInstance(char chainPrefix,
virNWFilterDefPtr nwfilter, virNWFilterDefPtr nwfilter,
virNWFilterRuleDefPtr rule, virNWFilterRuleDefPtr rule,
const char *ifname, const char *ifname,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
virNWFilterRuleInstPtr res, virNWFilterRuleInstPtr res,
bool reverse) bool reverse)
{ {
@ -2445,7 +2434,7 @@ ebiptablesCreateRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED,
virNWFilterDefPtr nwfilter, virNWFilterDefPtr nwfilter,
virNWFilterRuleDefPtr rule, virNWFilterRuleDefPtr rule,
const char *ifname, const char *ifname,
virNWFilterHashTablePtr vars, virNWFilterVarCombIterPtr vars,
virNWFilterRuleInstPtr res) virNWFilterRuleInstPtr res)
{ {
int rc = 0; int rc = 0;
@ -2529,6 +2518,44 @@ ebiptablesCreateRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED,
return rc; 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 static int
ebiptablesFreeRuleInstance(void *_inst) ebiptablesFreeRuleInstance(void *_inst)
@ -3796,7 +3823,7 @@ virNWFilterTechDriver ebiptables_driver = {
.init = ebiptablesDriverInit, .init = ebiptablesDriverInit,
.shutdown = ebiptablesDriverShutdown, .shutdown = ebiptablesDriverShutdown,
.createRuleInstance = ebiptablesCreateRuleInstance, .createRuleInstance = ebiptablesCreateRuleInstanceIterate,
.applyNewRules = ebiptablesApplyNewRules, .applyNewRules = ebiptablesApplyNewRules,
.tearNewRules = ebiptablesTearNewRules, .tearNewRules = ebiptablesTearNewRules,
.tearOldRules = ebiptablesTearOldRules, .tearOldRules = ebiptablesTearOldRules,