summaryrefslogtreecommitdiff
path: root/keama
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2017-11-16 10:18:20 +0100
committerFrancis Dupont <fdupont@isc.org>2018-11-29 16:42:23 +0100
commitcfbfdea78345863b7710b8d3e50073edf64c51b8 (patch)
tree11191fdb42916e9b845f432df2cafcd06b048b23 /keama
parent47e8943bd4a5753b88dfa052371fa1fa7990324c (diff)
downloadisc-dhcp-cfbfdea78345863b7710b8d3e50073edf64c51b8.tar.gz
Added match-if (aka guard) with match
Diffstat (limited to 'keama')
-rw-r--r--keama/confparse.c97
-rw-r--r--keama/tests/badclass.err15
-rw-r--r--keama/tests/badclass.msg1
-rw-r--r--keama/tests/badclass2.err15
-rw-r--r--keama/tests/badclass2.msg1
-rw-r--r--keama/tests/subclassguard4.in427
-rw-r--r--keama/tests/subclassguard4.out80
-rw-r--r--keama/tests/subclassguard6.in627
-rw-r--r--keama/tests/subclassguard6.out85
9 files changed, 309 insertions, 39 deletions
diff --git a/keama/confparse.c b/keama/confparse.c
index 103ff5de..80888538 100644
--- a/keama/confparse.c
+++ b/keama/confparse.c
@@ -224,6 +224,7 @@ post_process_classes(struct parse *cfile)
struct element *class;
struct element *name;
struct element *entry;
+ struct element *reduced;
struct string *msg;
struct comment *comment;
isc_boolean_t lose;
@@ -310,13 +311,21 @@ post_process_classes(struct parse *cfile)
entry = mapGet(class, "match-if");
if (entry == NULL)
continue;
+ reduced = mapGet(class, "test");
lose = ISC_FALSE;
- msg = makeString(-1, "/// match if: ");
+ if (reduced != NULL)
+ msg = makeString(-1, "/// from: match if ");
+ else
+ msg = makeString(-1, "/// match if ");
appendString(msg, print_boolean_expression(entry, &lose));
if (!lose) {
comment = createComment(msg->content);
- TAILQ_INSERT_TAIL(&class->comments, comment);
- mapRemove(class, "match-if");
+ if (reduced != NULL) {
+ TAILQ_INSERT_TAIL(&reduced->comments, comment);
+ mapRemove(class, "match-if");
+ continue;
+ }
+ TAILQ_INSERT_TAIL(&entry->comments, comment);
}
}
}
@@ -1436,6 +1445,8 @@ parse_class_declaration(struct parse *cfile, int type)
int declaration = 0;
struct string *name;
isc_boolean_t lose = ISC_FALSE;
+ isc_boolean_t matchedonce = ISC_FALSE;
+ isc_boolean_t submatchedonce = ISC_FALSE;
token = next_token(&val, NULL, cfile);
if (token != STRING)
@@ -1632,13 +1643,6 @@ parse_class_declaration(struct parse *cfile, int type)
if (pc)
parse_error(cfile,
"invalid match in subclass.");
- if (mapContains(class, "spawning") ||
- mapContains(class, "match-if") ||
- mapContains(class, "submatch") ||
- mapContains(class, "test"))
- parse_error(cfile,
- "A class may only have "
- "one 'match' or 'spawn' clause.");
token = peek_token(&val, NULL, cfile);
if (token != IF) {
expr = createBool(ISC_FALSE);
@@ -1646,13 +1650,21 @@ parse_class_declaration(struct parse *cfile, int type)
mapSet(class, expr, "spawning");
goto submatch;
}
+
skip_token(&val, NULL, cfile);
+ if (matchedonce)
+ parse_error(cfile,
+ "A class may only have "
+ "one 'match if' clause.");
+ matchedonce = ISC_TRUE;
expr = createMap();
if (!parse_boolean_expression(expr, cfile, &lose)) {
if (!lose)
parse_error(cfile,
"expecting boolean expr.");
} else {
+ expr->skip = ISC_TRUE;
+ mapSet(class, expr, "match-if");
add_match_class(cfile, class, copy(expr));
parse_semi(cfile);
}
@@ -1661,13 +1673,6 @@ parse_class_declaration(struct parse *cfile, int type)
if (pc)
parse_error(cfile,
"invalid spawn in subclass.");
- if (mapContains(class, "spawning") ||
- mapContains(class, "match-if") ||
- mapContains(class, "submatch") ||
- mapContains(class, "test"))
- parse_error(cfile,
- "A class may only have "
- "one 'match' or 'spawn' clause.");
expr = createBool(ISC_TRUE);
expr->skip = ISC_TRUE;
cfile->issue_counter++;
@@ -1677,6 +1682,11 @@ parse_class_declaration(struct parse *cfile, int type)
parse_error(cfile,
"expecting with after spawn");
submatch:
+ if (submatchedonce)
+ parse_error(cfile,
+ "can't override existing "
+ "submatch/spawn");
+ submatchedonce = ISC_TRUE;
expr = createMap();
if (!parse_data_expression(expr, cfile, &lose)) {
if (!lose)
@@ -1731,8 +1741,10 @@ subclass_inherit(struct parse *cfile,
struct element *superclass)
{
struct string *name;
+ struct element *guard;
struct element *submatch;
struct handle *handle;
+ struct string *gmsg;
struct string *mmsg;
struct string *dmsg;
struct element *expr;
@@ -1749,11 +1761,12 @@ subclass_inherit(struct parse *cfile,
if (expr == NULL)
parse_error(cfile, "can't get superclass name");
name = stringValue(expr);
+ guard = mapGet(superclass, "match-if");
submatch = mapGet(superclass, "submatch");
if (submatch == NULL)
parse_error(cfile, "can't get superclass submatch");
- /* Iterates on (copy of) superclass entrie */
+ /* Iterates on (copy of) superclass entries */
while (mapSize(superclass) > 0) {
handle = mapPop(superclass);
if ((handle == NULL) || (handle->key == NULL) ||
@@ -1764,6 +1777,8 @@ subclass_inherit(struct parse *cfile,
/* Superclass specific entries */
if ((strcmp(handle->key, "name") == 0) ||
(strcmp(handle->key, "spawning") == 0) ||
+ (strcmp(handle->key, "match-if") == 0) ||
+ (strcmp(handle->key, "test") == 0) ||
(strcmp(handle->key, "submatch") == 0))
continue;
/* Subclass specific so impossible entries */
@@ -1807,7 +1822,7 @@ subclass_inherit(struct parse *cfile,
mapSet(class, handle->value, handle->key);
}
- /* build submatch = data */
+ /* build [guard and] submatch = data */
expr = mapGet(class, "binary");
if (expr != NULL) {
data = createMap();
@@ -1822,8 +1837,22 @@ subclass_inherit(struct parse *cfile,
mapSet(match, copy(data), "right");
expr = createMap();
mapSet(expr, match, "equal");
-
- mmsg = makeString(-1, "/// from: match ");
+
+ if (guard != NULL) {
+ match = createMap();
+ mapSet(match, copy(guard), "left");
+ mapSet(match, expr, "right");
+ expr = createMap();
+ mapSet(expr, match, "and");
+
+ gmsg = makeString(-1, "/// from: match-if ");
+ appendString(gmsg, print_boolean_expression(guard, &lose));
+ mmsg = makeString(-1, "/// match: ");
+ } else {
+ gmsg = NULL;
+ mmsg = makeString(-1, "/// from: match ");
+ }
+
appendString(mmsg, print_data_expression(submatch, &lose));
dmsg = makeString(-1, "/// data: ");
appendString(dmsg, print_data_expression(data, &lose));
@@ -1839,6 +1868,10 @@ subclass_inherit(struct parse *cfile,
if ((reduced == NULL) || (reduced->type != ELEMENT_STRING))
return;
if (!lose) {
+ if (gmsg != NULL) {
+ comment = createComment(gmsg->content);
+ TAILQ_INSERT_TAIL(&reduced->comments, comment);
+ }
comment = createComment(mmsg->content);
TAILQ_INSERT_TAIL(&reduced->comments, comment);
comment = createComment(dmsg->content);
@@ -1857,15 +1890,8 @@ add_match_class(struct parse *cfile,
struct element *expr)
{
struct element *reduced;
- struct comment *comment = NULL;
- struct string *msg;
- isc_boolean_t lose = ISC_FALSE;
isc_boolean_t modified = ISC_FALSE;
-
- msg = makeString(-1, "/// from: match if ");
- appendString(msg, print_boolean_expression(expr, &lose));
- if (!lose)
- comment = createComment(msg->content);
+ isc_boolean_t lose = ISC_FALSE;
/* evaluate the expression and try to reduce it */
reduced = eval_boolean_expression(expr, &modified);
@@ -1874,17 +1900,10 @@ add_match_class(struct parse *cfile,
parse_error(cfile, "'match if' with a constant boolean "
"expression %s",
print_boolean_expression(expr, &lose));
- if ((reduced == NULL) || (reduced->type != ELEMENT_STRING)) {
- expr->skip = ISC_TRUE;
- cfile->issue_counter++;
- if (comment != NULL)
- TAILQ_INSERT_TAIL(&expr->comments, comment);
- mapSet(class, expr, "match-if");
- } else {
- if (comment != NULL)
- TAILQ_INSERT_TAIL(&reduced->comments, comment);
+ if ((reduced != NULL) && (reduced->type == ELEMENT_STRING))
mapSet(class, reduced, "test");
- }
+ else
+ cfile->issue_counter++;
}
/* Move pools to subnets */
diff --git a/keama/tests/badclass.err b/keama/tests/badclass.err
new file mode 100644
index 00000000..067345c2
--- /dev/null
+++ b/keama/tests/badclass.err
@@ -0,0 +1,15 @@
+# bad (double match-if) class declaration config
+
+# authoritative is mandatory
+authoritative;
+
+# options
+option mysystem code 250 = text;
+option myversion code 251 = unsigned integer 16;
+
+# class declaration
+class "foobar" {
+ match if option mysystem = "version1";
+ match if option mysystem = "version2";
+ option myversion 1;
+}
diff --git a/keama/tests/badclass.msg b/keama/tests/badclass.msg
new file mode 100644
index 00000000..fa1d033f
--- /dev/null
+++ b/keama/tests/badclass.msg
@@ -0,0 +1 @@
+badclass.err line 13: A class may only have one 'match if' clause.
diff --git a/keama/tests/badclass2.err b/keama/tests/badclass2.err
new file mode 100644
index 00000000..14f0bd48
--- /dev/null
+++ b/keama/tests/badclass2.err
@@ -0,0 +1,15 @@
+# bad (2 match) class declaration config
+
+# authoritative is mandatory
+authoritative;
+
+# options
+option mysystem code 250 = text;
+option myversion code 251 = unsigned integer 16;
+
+# superclass declaration
+class "foobar" {
+ match option mysystem;
+ match option myversion;
+ option myversion 1;
+}
diff --git a/keama/tests/badclass2.msg b/keama/tests/badclass2.msg
new file mode 100644
index 00000000..b79865b3
--- /dev/null
+++ b/keama/tests/badclass2.msg
@@ -0,0 +1 @@
+badclass2.err line 13: can't override existing submatch/spawn
diff --git a/keama/tests/subclassguard4.in4 b/keama/tests/subclassguard4.in4
new file mode 100644
index 00000000..500f9408
--- /dev/null
+++ b/keama/tests/subclassguard4.in4
@@ -0,0 +1,27 @@
+# subclass with guard declaration config
+
+# authoritative is mandatory
+authoritative;
+
+# options
+option mysystem code 250 = text;
+option myversion code 251 = unsigned integer 16;
+option mydescr code 252 = text;
+
+# superclass declaration
+class "foobar" {
+ match if option myversion = 0:1;
+ match option mysystem;
+}
+
+# simple subclass declaration
+subclass "foobar" "system1";
+
+# option setting subclass declaration
+subclass "foobar" "system2" { option mydescr "1.2"; }
+
+# complex subclass declaration
+subclass "foobar" "system3" {
+ option mydescr "1.3";
+ next-server 192.168.0.1;
+}
diff --git a/keama/tests/subclassguard4.out b/keama/tests/subclassguard4.out
new file mode 100644
index 00000000..49979131
--- /dev/null
+++ b/keama/tests/subclassguard4.out
@@ -0,0 +1,80 @@
+{
+ # subclass with guard declaration config
+ # authoritative is mandatory
+ "Dhcp4": {
+ "option-def": [
+ # options
+ {
+ "space": "dhcp4",
+ "name": "mysystem",
+ "code": 250,
+ "type": "string"
+ },
+ {
+ "space": "dhcp4",
+ "name": "myversion",
+ "code": 251,
+ "type": "uint16"
+ },
+ {
+ "space": "dhcp4",
+ "name": "mydescr",
+ "code": 252,
+ "type": "string"
+ }
+ ],
+ "client-classes": [
+ # superclass declaration
+ /// match: option dhcp.mysystem
+ {
+ "name": "foobar",
+ /// from: match if (option dhcp.myversion) = 0x0001
+ "test": "option[251].hex == 0x0001"
+ },
+ # simple subclass declaration
+ /// subclass selector 'system1'
+ {
+ "name": "sub#foobar#0",
+ /// from: match-if (option dhcp.myversion) = 0x0001
+ /// match: option dhcp.mysystem
+ /// data: 'system1'
+ "test": "(option[251].hex == 0x0001) and (option[250].hex == 'system1')"
+ },
+ # option setting subclass declaration
+ /// subclass selector 'system2'
+ {
+ "name": "sub#foobar#1",
+ "option-data": [
+ {
+ "space": "dhcp4",
+ "name": "mydescr",
+ "code": 252,
+ "data": "1.2"
+ }
+ ],
+ /// from: match-if (option dhcp.myversion) = 0x0001
+ /// match: option dhcp.mysystem
+ /// data: 'system2'
+ "test": "(option[251].hex == 0x0001) and (option[250].hex == 'system2')"
+ },
+ # complex subclass declaration
+ /// subclass selector 'system3'
+ {
+ "name": "sub#foobar#2",
+ "option-data": [
+ {
+ "space": "dhcp4",
+ "name": "mydescr",
+ "code": 252,
+ "data": "1.3"
+ }
+ ],
+ "next-server": "192.168.0.1",
+ /// from: match-if (option dhcp.myversion) = 0x0001
+ /// match: option dhcp.mysystem
+ /// data: 'system3'
+ "test": "(option[251].hex == 0x0001) and (option[250].hex == 'system3')"
+ }
+ ]
+ }
+}
diff --git a/keama/tests/subclassguard6.in6 b/keama/tests/subclassguard6.in6
new file mode 100644
index 00000000..51b6e28a
--- /dev/null
+++ b/keama/tests/subclassguard6.in6
@@ -0,0 +1,27 @@
+# subclass with guard declaration config
+
+# authoritative is mandatory
+authoritative;
+
+# options
+option dhcp6.mysystem code 1250 = text;
+option dhcp6.myversion code 1251 = unsigned integer 16;
+option dhcp6.mydescr code 1252 = text;
+
+# superclass declaration
+class "foobar" {
+ match if option dhcp6.myversion = 0:1;
+ match option dhcp6.mysystem;
+}
+
+# simple subclass declaration
+subclass "foobar" "system1";
+
+# option setting subclass declaration
+subclass "foobar" "system2" { option dhcp6.mydescr "1.2"; }
+
+# complex subclass declaration
+subclass "foobar" "system3" {
+ option dhcp6.mydescr "1.3";
+ option dhcp6.rapid-commit;
+}
diff --git a/keama/tests/subclassguard6.out b/keama/tests/subclassguard6.out
new file mode 100644
index 00000000..11387123
--- /dev/null
+++ b/keama/tests/subclassguard6.out
@@ -0,0 +1,85 @@
+{
+ # subclass with guard declaration config
+ # authoritative is mandatory
+ "Dhcp6": {
+ "option-def": [
+ # options
+ {
+ "space": "dhcp6",
+ "name": "mysystem",
+ "code": 1250,
+ "type": "string"
+ },
+ {
+ "space": "dhcp6",
+ "name": "myversion",
+ "code": 1251,
+ "type": "uint16"
+ },
+ {
+ "space": "dhcp6",
+ "name": "mydescr",
+ "code": 1252,
+ "type": "string"
+ }
+ ],
+ "client-classes": [
+ # superclass declaration
+ /// match: option dhcp6.mysystem
+ {
+ "name": "foobar",
+ /// from: match if (option dhcp6.myversion) = 0x0001
+ "test": "option[1251].hex == 0x0001"
+ },
+ # simple subclass declaration
+ /// subclass selector 'system1'
+ {
+ "name": "sub#foobar#0",
+ /// from: match-if (option dhcp6.myversion) = 0x0001
+ /// match: option dhcp6.mysystem
+ /// data: 'system1'
+ "test": "(option[1251].hex == 0x0001) and (option[1250].hex == 'system1')"
+ },
+ # option setting subclass declaration
+ /// subclass selector 'system2'
+ {
+ "name": "sub#foobar#1",
+ "option-data": [
+ {
+ "space": "dhcp6",
+ "name": "mydescr",
+ "code": 1252,
+ "data": "1.2"
+ }
+ ],
+ /// from: match-if (option dhcp6.myversion) = 0x0001
+ /// match: option dhcp6.mysystem
+ /// data: 'system2'
+ "test": "(option[1251].hex == 0x0001) and (option[1250].hex == 'system2')"
+ },
+ # complex subclass declaration
+ /// subclass selector 'system3'
+ {
+ "name": "sub#foobar#2",
+ "option-data": [
+ {
+ "space": "dhcp6",
+ "name": "mydescr",
+ "code": 1252,
+ "data": "1.3"
+ },
+ {
+ "space": "dhcp6",
+ "name": "rapid-commit",
+ "code": 14,
+ "data": ""
+ }
+ ],
+ /// from: match-if (option dhcp6.myversion) = 0x0001
+ /// match: option dhcp6.mysystem
+ /// data: 'system3'
+ "test": "(option[1251].hex == 0x0001) and (option[1250].hex == 'system3')"
+ }
+ ]
+ }
+}