Introduce possibility to have an iterator per variable

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>
This commit is contained in:
Stefan Berger 2012-01-11 06:42:37 -05:00 committed by Stefan Berger
parent 134c56764f
commit 80e9a5cd4c
8 changed files with 308 additions and 104 deletions

View File

@ -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>

View File

@ -272,13 +272,13 @@ virNWFilterRuleDefFree(virNWFilterRuleDefPtr def) {
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(virNWFilterRuleDefPtr nwf,
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) {
if (VIR_EXPAND_N(nwf->varAccess, nwf->nVarAccess, 1) < 0) {
virReportOOMError();
return -1;
}
nwf->vars[nwf->nvars] = strdup(var);
if (!nwf->vars[nwf->nvars]) {
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(virBufferPtr buf,
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;

View File

@ -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;

View File

@ -310,10 +310,11 @@ virNWFilterVarCombIterEntryInit(virNWFilterVarCombIterEntryPtr cie,
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 @@ virNWFilterVarCombIterEntryAreUniqueEntries(virNWFilterVarCombIterEntryPtr cie,
*/
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(virNWFilterHashTablePtr hash,
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(virBufferPtr buf,
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;
}

View File

@ -91,6 +91,38 @@ int virNWFilterHashTablePutAll(virNWFilterHashTablePtr src,
# 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 */

View File

@ -832,6 +832,7 @@ virNWFilterHashTableFree;
virNWFilterHashTablePut;
virNWFilterHashTablePutAll;
virNWFilterHashTableRemoveEntry;
virNWFilterVarAccessGetVarName;
virNWFilterVarCombIterCreate;
virNWFilterVarCombIterFree;
virNWFilterVarCombIterGetVarValue;

View File

@ -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;

View File

@ -500,14 +500,16 @@ virNWFilterDetermineMissingVarsRec(virNWFilterDefPtr filter,
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);
}
}