diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng
index 6a9c7bc108..bce3d3b838 100644
--- a/docs/schemas/nwfilter.rng
+++ b/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}
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c
index 0d6ce04928..5db4562128 100644
--- a/src/conf/nwfilter_conf.c
+++ b/src/conf/nwfilter_conf.c
@@ -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;
diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h
index 42b465fd42..4331ab1831 100644
--- a/src/conf/nwfilter_conf.h
+++ b/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;
diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c
index b009edf152..c1a8aed881 100644
--- a/src/conf/nwfilter_params.c
+++ b/src/conf/nwfilter_params.c
@@ -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[@] -> 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;
+}
diff --git a/src/conf/nwfilter_params.h b/src/conf/nwfilter_params.h
index 81f104920b..a62d09ac54 100644
--- a/src/conf/nwfilter_params.h
+++ b/src/conf/nwfilter_params.h
@@ -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 */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ac2c52e1e9..0abce7052a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -832,6 +832,7 @@ virNWFilterHashTableFree;
virNWFilterHashTablePut;
virNWFilterHashTablePutAll;
virNWFilterHashTableRemoveEntry;
+virNWFilterVarAccessGetVarName;
virNWFilterVarCombIterCreate;
virNWFilterVarCombIterFree;
virNWFilterVarCombIterGetVarValue;
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index 9c244be41c..8ddc2d5597 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/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;
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index 5385d91268..fe9a3a7e13 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -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);
}
}