assigned to members of this class. In the case of a template class, these
options are assigned to the generated spawned class.
- The ``option-def`` list is not mandatory and is used to define custom options.
- - The ``only-if-required`` flag is not mandatory; when its value is set to
+ - The ``only-if-required`` has been replaced with ``only-in-additional-list`` and
+ is now deprecated. It will still be accepted as input for a time to allow users
+ to migrate but will eventually be unsupported.
+ - The ``only-in-additional-list`` flag is not mandatory; when its value is set to
``false`` (the default), membership is determined during classification and is
available for subnet selection, for instance. When the value is set to
- ``true``, membership is evaluated only when required and is usable only for
- option configuration.
+ ``true``, membership is evaluated only if the class appears in an ``evaluate-
+ additional-classes`` list and is usable only for option configuration.
- The ``user-context`` is not mandatory and represents a map with user-defined data
and possibly configuration options for hook libraries.
- The ``next-server`` parameter is not mandatory and configures the ``siaddr`` field in
Usually the ``test`` and ``template-test`` expressions are evaluated before
subnet selection, but in some cases it is useful to evaluate it later when the
subnet, shared network, or pools are known but output-option processing has not
-yet been done. For this purpose, the ``only-if-required`` flag, which is
+yet been done. For this purpose, the ``only-in-additional-list`` flag, which is
``false`` by default, allows the evaluation of the ``test`` expression or the
-``template-test`` expression only when it is required, i.e. in a
-``require-client-classes`` list of the selected pool, subnet, or shared network.
+``template-test`` expression only when it is required by the class's presence
+in the ``evaluate-additional-classes`` list of the selected pool, subnet, or
+shared network.
-The ``require-client-classes`` list, which is valid for pool, subnet,
+The ``evaluate-additional-classes`` list, which is valid for pool, subnet,
and shared-network scope, specifies the classes which are evaluated in
the second pass before output-option processing. The list is built in
-same precedence order of the option data, i.e. an option data item in
-a subnet takes precedence over one in a shared network, and also a
-required class in a subnet is added before one in a shared
-network. The mechanism is related to the ``only-if-required`` flag but
+same precedence order as the option data, i.e. an option data item in
+a subnet takes precedence over one in a shared network. An
+additional class in a subnet is added before one in a shared
+network. The mechanism is related to the ``only-in-additional-list`` flag but
it is not mandatory that the flag be set to ``true``.
.. note ::
Option Class-Tagging
====================
-Option class-tagging allows an option value to conditionally applied
-to the response based on the client's class membership. The effect is
-similar to using an if-block in ISC DHCP to conditionally include
+Option class-tagging allows an option value to conditionally applied
+to the response based on the client's class membership. The effect is
+similar to using an if-block in ISC DHCP to conditionally include
options at a given scope. Class-tagging is done by specifying a list of
one of more class names in the option's ``client-classes`` entry.
before the response is to be sent to the client.
-When ``never-send`` for an option is true at any scope, all
+When ``never-send`` for an option is true at any scope, all
``client-classes`` entries for that option are ignored. The
option will not included.
-When ``always-send`` is true at any scope, the option will be
-included unless, the option determined by scope specifies
-a ``client-classes`` list that does not contain any of the
+When ``always-send`` is true at any scope, the option will be
+included unless, the option determined by scope specifies
+a ``client-classes`` list that does not contain any of the
client's classes.
-Otherwise, An option requested by the client will be included in
+Otherwise, An option requested by the client will be included in
the response if the option either does not specify ``client-classes``
or the client belongs to at least one of the classes in ``client-classes``.
-When an option's class-tag does not match, it is as though
+When an option's class-tag does not match, it is as though
the option was not specified at that scope. In the following
example the option "foo" is specified for both the subnet and
the pool. The pool specification includes a class-tag that limits
-the option to members of class "melon":
+the option to members of class "melon":
::
}]
}]
}
-
+
Clients that match class "melon" will have a value of 123 for option "foo",
while clients that do not match "melon" will have a value of 456 for option
-"foo".
+"foo".
.. note::
- Though examples above are for DHCPv4, class-tagging syntax and
- behavior is the same for DHPCv6.
+ Though examples above are for DHCPv4, class-tagging syntax and
+ behavior is the same for DHPCv6.
Classes and Hooks
=================
...
}
-.. _dhcp4-required-class:
+.. _dhcp4-additional-class:
-Required Classification
-~~~~~~~~~~~~~~~~~~~~~~~
+Additional Classification
+~~~~~~~~~~~~~~~~~~~~~~~~~
In some cases it is useful to limit the scope of a class to a pool,
subnet, or shared network. There are two parameters which are used
to limit the scope of the class by instructing the server to evaluate test
expressions when required.
-The first one is the per-class ``only-if-required`` flag, which is ``false``
-by default. When it is set to ``true``, the test expression of the class
-is not evaluated at the reception of the incoming packet but later, and
-only if the class evaluation is required.
-
-The second is ``require-client-classes``, which takes a list of class
+The ``evaluate-additional-classes``, which takes a list of class
names and is valid in pool, subnet, and shared network scope. Classes in
-these lists are marked as required and evaluated after selection of this
+these lists are marked as additional and evaluated after selection of this
specific pool/subnet/shared network and before output-option processing.
+The second one is the per-class ``only-in-additional-list`` flag, which is
+``false`` by default. When it is set to ``true``, the test expression of
+the class is not evaluated at the reception of the incoming packet but later,
+and only if the class is present in an ``evaluate-additional-classes`` list.
+
In this example, a class is assigned to the incoming packet when the
specified subnet is used:
{
"name": "Client_foo",
"test": "member('ALL')",
- "only-if-required": true
+ "only-in-additional-list": true
},
...
],
{
"subnet": "192.0.2.0/24",
"pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
- "require-client-classes": [ "Client_foo" ],
+ "evaluate-additional-classes": [ "Client_foo" ],
...
},
...
...
}
-Required evaluation can be used to express complex dependencies like
+Additional evaluation can be used to express complex dependencies like
subnet membership. It can also be used to reverse the
precedence; if ``option-data`` is set in a subnet, it takes precedence
over ``option-data`` in a class. If ``option-data`` is moved to a
required class and required in the subnet, a class evaluated earlier
may take precedence.
-Required evaluation is also available at the shared network and pool levels.
-The order in which required classes are considered is: pool, subnet,
+Additional evaluation is also available at the shared network and pool levels.
+The order in which additional classes are considered is: pool, subnet,
and shared network, i.e. in the same order from the way in which
``option-data`` is processed.
-Since Kea version 2.7.4 required client classes configured without
+Since Kea version 2.7.4 additional client classes configured without
a test expression are unconditionally added, i.e. they are considered
to always be evaluated to ``true``.
+.. note::
+
+ As of Kea version 2.7.4, ``only-if-required`` and ``require-client-classes``
+ have been renamed to ``only-in-additional-list`` and ``evaluate-additional-classes``
+ respectivley. The original names will still be accepted as input to allow
+ users to migrate but will eventually be unsupported.
+
.. note::
Vendor-Identifying Vendor Options are a special case: for all other
{
"name": "dependent-class",
"test": "member('KNOWN')",
- "only-if-required": true
+ "only-in-additional-list": true
}
]
}
-The ``only-if-required`` parameter is needed here to force evaluation
+The ``only-in-additional-list`` parameter is needed here to force evaluation
of the class after the lease has been allocated, and thus the reserved
class has been also assigned.
The classes specified in non-global host reservations
are assigned to the processed packet after all classes with the
- ``only-if-required`` parameter set to ``false`` have been evaluated.
+ ``only-in-additional-list`` parameter set to ``false`` have been evaluated.
This means that these classes must not depend on the
statically assigned classes from the host reservations. If
- such a dependency is needed, the ``only-if-required`` parameter must
+ such a dependency is needed, the ``only-in-additional-list`` parameter must
be set to ``true`` for the dependent classes. Such classes are
evaluated after the static classes have been assigned to the packet.
This, however, imposes additional configuration overhead, because
- all classes marked as ``only-if-required`` must be listed in the
- ``require-client-classes`` list for every subnet where they are used.
+ all classes marked as ``only-in-additional-list`` must be listed in the
+ ``evaluate-additional-classes`` list for every subnet where they are used.
.. note::
Client classes specified within the Kea configuration file may
depend on the classes specified within the global host reservations.
- In such a case the ``only-if-required`` parameter is not needed.
+ In such a case the ``only-in-additional-list`` parameter is not needed.
Refer to :ref:`pool-selection-with-class-reservations4` and
:ref:`subnet-selection-with-class-reservations4`
for specific use cases.
supported at the subnet, shared network, client class, and global levels. It
must not be specified at the host-reservation level.
When configuring the ``dhcp-server-identifier`` option at client-class level, the
-class must not set the ``only-if-required`` flag, because this class would not
+class must not set the ``only-in-additional-list`` flag, because this class would not
be evaluated before the server determines if the received DHCP message should
be accepted for processing. Such classes are evaluated after subnet selection.
-See :ref:`dhcp4-required-class` for details.
+See :ref:`dhcp4-additional-class` for details.
The following example demonstrates how to override the server identifier
for a subnet:
...
}
-.. _dhcp6-required-class:
+.. _dhcp6-additional-class:
-Required Classification
-~~~~~~~~~~~~~~~~~~~~~~~
+Additional Classification
+~~~~~~~~~~~~~~~~~~~~~~~~~
In some cases it is useful to limit the scope of a class to a pool,
subnet, or shared network. There are two parameters which are used
to limit the scope of the class by instructing the server to evaluate test
expressions when required.
-The first one is the per-class ``only-if-required`` flag, which is ``false``
-by default. When it is set to ``true``, the test expression of the class
-is not evaluated at the reception of the incoming packet but later, and
-only if the class evaluation is required.
-
-The second is ``require-client-classes``, which takes a list of class
+The ``evaluate-additional-classes``, which takes a list of class
names and is valid in pool, subnet, and shared network scope. Classes in
-these lists are marked as required and evaluated after selection of this
+these lists are marked as additional and evaluated after selection of this
specific pool/subnet/shared network and before output-option processing.
+The second one is the per-class ``only-in-additional-list`` flag, which is
+``false`` by default. When it is set to ``true``, the test expression of
+the class is not evaluated at the reception of the incoming packet but later,
+and only if the class is present in an ``evaluate-additional-classes`` list.
+
In this example, a class is assigned to the incoming packet when the
specified subnet is used:
{
"name": "Client_foo",
"test": "member('ALL')",
- "only-if-required": true
+ "only-in-additional-list": true
},
...
],
"pool": "2001:db8:1::-2001:db8:1::ffff"
}
],
- "require-client-classes": [ "Client_foo" ],
+ "evaluate-additional-classes": [ "Client_foo" ],
...
},
...
...
}
-Required evaluation can be used to express complex dependencies like
+Additional evaluation can be used to express complex dependencies like
subnet membership. It can also be used to reverse the
precedence; if ``option-data`` is set in a subnet, it takes precedence
over ``option-data`` in a class. If ``option-data`` is moved to a
required class and required in the subnet, a class evaluated earlier
may take precedence.
-Required evaluation is also available at shared network and pool/pd-pool
-levels. The order in which required classes are considered is:
+Additional evaluation is also available at shared network and pool/pd-pool
+levels. The order in which additional classes are considered is:
(pd-)pool, subnet, and shared network, i.e. in the same order from the
way in which ``option-data`` is processed.
-Since Kea version 2.7.4 required client classes configured without
+Since Kea version 2.7.4 additional classes configured without
a test expression are unconditionally added, i.e. they are considered
to always be evaluated to ``true``.
+.. note::
+
+ As of Kea version 2.7.4, ``only-if-required`` and ``require-client-classes``
+ have been renamed to ``only-in-additional-list`` and ``evaluate-additional-classes``
+ respectivley. The original names will still be accepted as input to allow
+ users to migrate but will eventually be unsupported.
+
.. _dhcp6-ddns-config:
DDNS for DHCPv6
{
"name": "dependent-class",
"test": "member('KNOWN')",
- "only-if-required": true
+ "only-in-additional-list": true
}
]
}
-The ``only-if-required`` parameter is needed here to force
+The ``only-in-additional-list`` parameter is needed here to force
evaluation of the class after the lease has been allocated and thus the
reserved class has been also assigned.
The classes specified in non-global host reservations
are assigned to the processed packet after all classes with the
- ``only-if-required`` parameter set to ``false`` have been evaluated.
+ ``only-in-additional-list` parameter set to ``false`` have been evaluated.
This means that these classes must not depend on the
statically assigned classes from the host reservations. If
- such a dependency is needed, the ``only-if-required`` must
+ such a dependency is needed, the ``only-in-addtional-list`` must
be set to ``true`` for the dependent classes. Such classes are
evaluated after the static classes have been assigned to the packet.
This, however, imposes additional configuration overhead, because
- all classes marked as ``only-if-required`` must be listed in the
- ``require-client-classes`` list for every subnet where they are used.
+ all classes marked as ``only-in-addtional-list`` must be listed in the
+ ``evaluate-additional-classes`` list for every subnet where they are used.
.. note::
Client classes specified within the Kea configuration file may
depend on the classes specified within the global host reservations.
- In such a case the ``only-if-required`` parameter is not needed.
+ In such a case the ``only-in-additional-list`` parameter is not needed.
Refer to the :ref:`pool-selection-with-class-reservations6` and
:ref:`subnet-selection-with-class-reservations6`
for specific use cases.
"client-classes": [
{
"name": "pxeclient",
- "only-if-required": true,
+ "only-in-additional-list": true,
"test": "option[vendor-class-identifier].text == 'PXEClient'",
"option-def": [
{
parameters are only returned by the DHCPv4 server and are never returned
by the DHCPv6 server. Also, some of the parameters provided in this
example may not be returned if they are not specified for the class.
-Specifically, ``only-if-required``, ``test``, and ``option-def`` are not
+Specifically, ``only-in-additional-list``, ``test``, and ``option-def`` are not
returned if they are not specified for the class.
+
+.. note::
+
+ As of Kea version 2.7.4, ``only-if-required`` has been replaced with
+ ``only-in-additional-list`` and deprecated. In order to allow users time
+ to migrate class commands will still accept it as input but translate it
+ to ``only-in-additional-list`` on output. Eventually support for the
+ old name wil be removed.
* ``lease6_renew``
* ``lease6_rebind``
-As a result, classes for which ``"only-if-required"`` is "true" cannot be lease-limited.
+As a result, classes for which ``"only-in-additional-list"`` is "true" cannot be lease-limited.
Please refer to :ref:`the classification steps <classify-classification-steps>` for more information on which
client classes can be used to limit the number of leases.
``pkt6_receive`` callout, respectively, so that rate limits are checked as early as possible in the
packet-processing cycle. Thus, only those classes which are assigned to the packet solely via an
independent test expression can be used. Classes that depend on host reservations or the special
-``BOOTP`` or ``KNOWN`` classes, and classes that are marked with ``"only-if-required": true``,
+``BOOTP`` or ``KNOWN`` classes, and classes that are marked with ``"only-in-additional-list": true``,
cannot be rate limited. See :ref:`the classification steps <classify-classification-steps>` for
more details on which client classes can be used to limit the packet rate.
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
return isc::dhcp::Dhcp4Parser::make_ONLY_IN_ADDITIONAL_LIST(driver.loc_);
default:
- return isc::dhcp::Dhcp4Parser::make_STRING("in-additional-list", driver.loc_);
+ return isc::dhcp::Dhcp4Parser::make_STRING("only-in-additional-list", driver.loc_);
}
}
YY_BREAK
case isc::dhcp::Parser4Context::CLIENT_CLASSES:
return isc::dhcp::Dhcp4Parser::make_ONLY_IN_ADDITIONAL_LIST(driver.loc_);
default:
- return isc::dhcp::Dhcp4Parser::make_STRING("in-additional-list", driver.loc_);
+ return isc::dhcp::Dhcp4Parser::make_STRING("only-in-additional-list", driver.loc_);
}
}
namespace isc {
namespace dhcp {
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_EVAL_ERROR = "DHCP4_ADDITIONAL_CLASS_EVAL_ERROR";
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_EVAL_RESULT = "DHCP4_ADDITIONAL_CLASS_EVAL_RESULT";
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_NO_TEST = "DHCP4_ADDITIONAL_CLASS_NO_TEST";
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_UNDEFINED = "DHCP4_ADDITIONAL_CLASS_UNDEFINED";
extern const isc::log::MessageID DHCP4_ALREADY_RUNNING = "DHCP4_ALREADY_RUNNING";
extern const isc::log::MessageID DHCP4_BUFFER_RECEIVED = "DHCP4_BUFFER_RECEIVED";
extern const isc::log::MessageID DHCP4_BUFFER_RECEIVE_FAIL = "DHCP4_BUFFER_RECEIVE_FAIL";
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_NO_LEASE = "DHCP4_RELEASE_FAIL_NO_LEASE";
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_WRONG_CLIENT = "DHCP4_RELEASE_FAIL_WRONG_CLIENT";
extern const isc::log::MessageID DHCP4_REQUEST = "DHCP4_REQUEST";
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_ERROR = "DHCP4_REQUIRED_CLASS_EVAL_ERROR";
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_RESULT = "DHCP4_REQUIRED_CLASS_EVAL_RESULT";
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_NO_TEST = "DHCP4_REQUIRED_CLASS_NO_TEST";
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_UNDEFINED = "DHCP4_REQUIRED_CLASS_UNDEFINED";
extern const isc::log::MessageID DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED = "DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED";
extern const isc::log::MessageID DHCP4_RESERVED_HOSTNAME_ASSIGNED = "DHCP4_RESERVED_HOSTNAME_ASSIGNED";
extern const isc::log::MessageID DHCP4_RESPONSE_DATA = "DHCP4_RESPONSE_DATA";
namespace {
const char* values[] = {
+ "DHCP4_ADDITIONAL_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3",
+ "DHCP4_ADDITIONAL_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
+ "DHCP4_ADDITIONAL_CLASS_NO_TEST", "additional class %1 has no test expression, adding it to client's classes unconditionally",
+ "DHCP4_ADDITIONAL_CLASS_UNDEFINED", "additional class %1 has no definition",
"DHCP4_ALREADY_RUNNING", "%1 already running? %2",
"DHCP4_BUFFER_RECEIVED", "received buffer from %1:%2 to %3:%4 over interface %5",
"DHCP4_BUFFER_RECEIVE_FAIL", "error on attempt to receive packet: %1",
"DHCP4_RELEASE_FAIL_NO_LEASE", "%1: client is trying to release non-existing lease %2",
"DHCP4_RELEASE_FAIL_WRONG_CLIENT", "%1: client is trying to release the lease %2 which belongs to a different client",
"DHCP4_REQUEST", "%1: server is processing DHCPREQUEST with hint=%2",
- "DHCP4_REQUIRED_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3",
- "DHCP4_REQUIRED_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
- "DHCP4_REQUIRED_CLASS_NO_TEST", "required class %1 has no test expression, adding it to client's classes unconditionally",
- "DHCP4_REQUIRED_CLASS_UNDEFINED", "required class %1 has no definition",
"DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED", "Multi-threading is enabled and host reservations lookup is always performed first.",
"DHCP4_RESERVED_HOSTNAME_ASSIGNED", "%1: server assigned reserved hostname %2",
"DHCP4_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4",
namespace isc {
namespace dhcp {
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_EVAL_ERROR;
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_EVAL_RESULT;
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_NO_TEST;
+extern const isc::log::MessageID DHCP4_ADDITIONAL_CLASS_UNDEFINED;
extern const isc::log::MessageID DHCP4_ALREADY_RUNNING;
extern const isc::log::MessageID DHCP4_BUFFER_RECEIVED;
extern const isc::log::MessageID DHCP4_BUFFER_RECEIVE_FAIL;
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_NO_LEASE;
extern const isc::log::MessageID DHCP4_RELEASE_FAIL_WRONG_CLIENT;
extern const isc::log::MessageID DHCP4_REQUEST;
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_ERROR;
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_RESULT;
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_NO_TEST;
-extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_UNDEFINED;
extern const isc::log::MessageID DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED;
extern const isc::log::MessageID DHCP4_RESERVED_HOSTNAME_ASSIGNED;
extern const isc::log::MessageID DHCP4_RESPONSE_DATA;
If there is no hint, the argument should provide the text indicating
that the hint hasn't been sent.
-% DHCP4_REQUIRED_CLASS_EVAL_ERROR %1: Expression '%2' evaluated to %3
+% DHCP4_ADDITIONAL_CLASS_EVAL_ERROR %1: Expression '%2' evaluated to %3
This error message indicates that there a problem was encountered while
-evaluating an expression of a required client class that was marked as required.
+evaluating an expression of a additional client class that was marked as additional.
A description of the problem is printed.
-% DHCP4_REQUIRED_CLASS_EVAL_RESULT %1: Expression '%2' evaluated to %3
+% DHCP4_ADDITIONAL_CLASS_EVAL_RESULT %1: Expression '%2' evaluated to %3
Logged at debug log level 50.
-This debug message indicates that the expression of a required client class has
+This debug message indicates that the expression of a additional client class has
been successfully evaluated. The client class name and the result value of the
evaluation are printed.
-% DHCP4_REQUIRED_CLASS_NO_TEST required class %1 has no test expression, adding it to client's classes unconditionally
+% DHCP4_ADDITIONAL_CLASS_NO_TEST additional class %1 has no test expression, adding it to client's classes unconditionally
Logged at debug log level 40.
-This debug message informs that a class was listed for required evaluation but
+This debug message informs that a class was listed for additional evaluation but
its definition does not include a test expression to evaluate. The class is
unconditionally added to the query.
-% DHCP4_REQUIRED_CLASS_UNDEFINED required class %1 has no definition
+% DHCP4_ADDITIONAL_CLASS_UNDEFINED additional class %1 has no definition
Logged at debug log level 40.
-This debug message informs that a class is listed for required evaluation but
+This debug message informs that a class is listed for additional evaluation but
has no definition. The class is ignored.
% DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED Multi-threading is enabled and host reservations lookup is always performed first.
// Check whether option has been configured.
for (auto const& copts : co_list) {
OptionDescriptor desc = copts->get(DHCP4_OPTION_SPACE, required);
- /// @todo TKM - not sure if otion class-tagging should be allowed here?
if (desc.option_ && desc.allowedForClientClasses(cclasses)) {
resp->addOption(desc.option_);
break;
const ClientClassDefPtr class_def = dict->findClass(cclass);
if (!class_def) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
- DHCP4_REQUIRED_CLASS_UNDEFINED)
+ DHCP4_ADDITIONAL_CLASS_UNDEFINED)
.arg(cclass);
// Ignore it as it can't have an attached action
continue;
// Add a class without an expression to evaluate
if (!expr_ptr) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
- DHCP4_REQUIRED_CLASS_NO_TEST)
+ DHCP4_ADDITIONAL_CLASS_NO_TEST)
.arg(cclass);
query->addClass(cclass);
continue;
// true (match) or raise an exception (error)
try {
bool status = evaluateBool(*expr_ptr, *query);
- LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_REQUIRED_CLASS_EVAL_RESULT)
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_ADDITIONAL_CLASS_EVAL_RESULT)
.arg(query->getLabel())
.arg(cclass)
.arg(status ? "true" : "false");
query->addClass(cclass);
}
} catch (const Exception& ex) {
- LOG_ERROR(dhcp4_logger, DHCP4_REQUIRED_CLASS_EVAL_ERROR)
+ LOG_ERROR(dhcp4_logger, DHCP4_ADDITIONAL_CLASS_EVAL_ERROR)
.arg(query->getLabel())
.arg(cclass)
.arg(ex.what());
"{"
" \"name\": \"pxe1\","
" \"test\": \"option[93].hex == 0x0009\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"next-server\": \"1.2.3.4\""
"},"
"{"
" \"name\": \"pxe2\","
" \"test\": \"option[93].hex == 0x0007\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"server-hostname\": \"deneb\""
"},"
"{"
" \"name\": \"pxe3\","
" \"test\": \"option[93].hex == 0x0006\","
- " \"only-if-required\": false,"
+ " \"only-in-additional-list\": false,"
" \"boot-file-name\": \"pxelinux.0\""
"},"
"{"
testFixedFields(CONFIGS[3], DHCPINFORM, OptionPtr(), "0.0.0.0", "", "");
}
-// Class 'pxe1' is only-if-required and not subject to required evaluation
+// Class 'pxe1' is only-in-additional-list and not subject to additional evaluation
TEST_F(ClassifyTest, fixedFieldsDiscoverNextServer3) {
OptionPtr pxe(new OptionInt<uint16_t>(Option::V4, 93, 0x0009));
testFixedFields(CONFIGS[3], DHCPINFORM, pxe, "0.0.0.0", "", "");
}
-// Class pxe2 is only-if-required but the subnet requires its evaluation
+// Class pxe2 is only-in-additional-list but the subnet requires its evaluation
TEST_F(ClassifyTest, fixedFieldsDiscoverHostname3) {
OptionPtr pxe(new OptionInt<uint16_t>(Option::V4, 93, 0x0007));
EXPECT_EQ("10.0.0.160", resp->getYiaddr().toText());
}
-// This test checks the precedence order in required evaluation.
+// This test checks the precedence order in additional evaluation.
// This order is: pools > subnet > shared-network
TEST_F(ClassifyTest, precedenceNone) {
std::string config =
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.3\""
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.3\""
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.3\""
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"domain-name-servers\","
" \"data\": \"10.0.0.3\""
R"^(
"rebind-timer": 2000,
"renew-timer": 1000,
- "subnet4": [{
- "require-client-classes": [ "foo" ],
- "pools": [{ "pool": "192.0.2.0/28" }],
- "id": 1,
- "subnet": "192.0.2.0/24"
+ "shared-networks":[{
+ "name": "net1",
+ "require-client-classes": [ "one" ],
+ "subnet4": [{
+ "require-client-classes": [ "two" ],
+ "pools": [{
+ "pool": "192.0.2.0/28",
+ "require-client-classes": [ "three" ]
+ }],
+ "id": 1,
+ "subnet": "192.0.2.0/24"
+ }],
}],
"valid-lifetime": 400
})^";
ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
checkResult(status, 0);
+ SharedNetwork4Ptr network = CfgMgr::instance().getStagingCfg()->
+ getCfgSharedNetworks4()->getByName("net1");
+ ASSERT_TRUE(network);
+
+ auto& net_class_list = network->getAdditionalClasses();
+ EXPECT_EQ(1, net_class_list.size());
+ auto cclasses = net_class_list.begin();
+ EXPECT_EQ(*cclasses, "one");
+
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.0"));
ASSERT_TRUE(subnet);
- const auto& cclass_list = subnet->getAdditionalClasses();
- EXPECT_EQ(1, cclass_list.size());
- auto cclasses = cclass_list.begin();
- EXPECT_EQ(*cclasses, "foo");
+ auto& sub_class_list = subnet->getAdditionalClasses();
+ EXPECT_EQ(1, sub_class_list.size());
+ cclasses = sub_class_list.begin();
+ EXPECT_EQ(*cclasses, "two");
+
+ PoolPtr pool = subnet->getPool(Lease::TYPE_V4, IOAddress("192.0.2.0"), false);
+ ASSERT_TRUE(pool);
+
+ auto& pool_class_list = pool->getAdditionalClasses();
+ EXPECT_EQ(1, pool_class_list.size());
+ cclasses = pool_class_list.begin();
+ EXPECT_EQ(*cclasses, "three");
// Now verify that users cannot specify both.
config = "{ " + genIfaceConfig() + ","
namespace dhcp {
extern const isc::log::MessageID DHCP4_HOOK_SUBNET6_SELECT_PARKING_LOT_FULL = "DHCP4_HOOK_SUBNET6_SELECT_PARKING_LOT_FULL";
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_ERROR = "DHCP6_ADDITIONAL_CLASS_EVAL_ERROR";
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_RESULT = "DHCP6_ADDITIONAL_CLASS_EVAL_RESULT";
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_NO_TEST = "DHCP6_ADDITIONAL_CLASS_NO_TEST";
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_UNDEFINED = "DHCP6_ADDITIONAL_CLASS_UNDEFINED";
extern const isc::log::MessageID DHCP6_ADD_GLOBAL_STATUS_CODE = "DHCP6_ADD_GLOBAL_STATUS_CODE";
extern const isc::log::MessageID DHCP6_ADD_STATUS_CODE_FOR_IA = "DHCP6_ADD_STATUS_CODE_FOR_IA";
extern const isc::log::MessageID DHCP6_ALREADY_RUNNING = "DHCP6_ALREADY_RUNNING";
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL = "DHCP6_RELEASE_PD_FAIL";
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_DUID = "DHCP6_RELEASE_PD_FAIL_WRONG_DUID";
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_IAID = "DHCP6_RELEASE_PD_FAIL_WRONG_IAID";
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_ERROR = "DHCP6_REQUIRED_CLASS_EVAL_ERROR";
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_RESULT = "DHCP6_REQUIRED_CLASS_EVAL_RESULT";
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_NO_TEST = "DHCP6_REQUIRED_CLASS_NO_TEST";
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_UNDEFINED = "DHCP6_REQUIRED_CLASS_UNDEFINED";
extern const isc::log::MessageID DHCP6_REQUIRED_OPTIONS_CHECK_FAIL = "DHCP6_REQUIRED_OPTIONS_CHECK_FAIL";
extern const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED = "DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED";
extern const isc::log::MessageID DHCP6_RESPONSE_DATA = "DHCP6_RESPONSE_DATA";
const char* values[] = {
"DHCP4_HOOK_SUBNET6_SELECT_PARKING_LOT_FULL", "The parked-packet-limit %1, has been reached, dropping query: %2",
+ "DHCP6_ADDITIONAL_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3",
+ "DHCP6_ADDITIONAL_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
+ "DHCP6_ADDITIONAL_CLASS_NO_TEST", "additional class %1 has no test expression, adding it to client's classes unconditionally",
+ "DHCP6_ADDITIONAL_CLASS_UNDEFINED", "additional class %1 has no definition",
"DHCP6_ADD_GLOBAL_STATUS_CODE", "%1: adding Status Code to DHCPv6 packet: %2",
"DHCP6_ADD_STATUS_CODE_FOR_IA", "%1: adding Status Code to IA with iaid=%2: %3",
"DHCP6_ALREADY_RUNNING", "%1 already running? %2",
"DHCP6_RELEASE_PD_FAIL", "%1: failed to release prefix %2/%3 for iaid=%4",
"DHCP6_RELEASE_PD_FAIL_WRONG_DUID", "%1: client tried to release prefix %2/%3, but it belongs to another client (duid=%4)",
"DHCP6_RELEASE_PD_FAIL_WRONG_IAID", "%1: client tried to release prefix %2/%3, but it used wrong IAID (expected %4, but got %5)",
- "DHCP6_REQUIRED_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3",
- "DHCP6_REQUIRED_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
- "DHCP6_REQUIRED_CLASS_NO_TEST", "required class %1 has no test expression, adding it to client's classes unconditionally",
- "DHCP6_REQUIRED_CLASS_UNDEFINED", "required class %1 has no definition",
"DHCP6_REQUIRED_OPTIONS_CHECK_FAIL", "%1: %2 message received from %3 failed the following check: %4",
"DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED", "Multi-threading is enabled and host reservations lookup is always performed first.",
"DHCP6_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4",
namespace dhcp {
extern const isc::log::MessageID DHCP4_HOOK_SUBNET6_SELECT_PARKING_LOT_FULL;
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_ERROR;
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_EVAL_RESULT;
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_NO_TEST;
+extern const isc::log::MessageID DHCP6_ADDITIONAL_CLASS_UNDEFINED;
extern const isc::log::MessageID DHCP6_ADD_GLOBAL_STATUS_CODE;
extern const isc::log::MessageID DHCP6_ADD_STATUS_CODE_FOR_IA;
extern const isc::log::MessageID DHCP6_ALREADY_RUNNING;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_DUID;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_IAID;
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_ERROR;
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_RESULT;
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_NO_TEST;
-extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_UNDEFINED;
extern const isc::log::MessageID DHCP6_REQUIRED_OPTIONS_CHECK_FAIL;
extern const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED;
extern const isc::log::MessageID DHCP6_RESPONSE_DATA;
argument identify the prefix. The fourth and fifth argument hold the
expected IAID and IAID found respectively.
-% DHCP6_REQUIRED_CLASS_EVAL_ERROR %1: Expression '%2' evaluated to %3
-This error message indicates that there a problem was encountered while
-evaluating an expression of a required client class that was marked as required.
+% DHCP6_ADDITIONAL_CLASS_EVAL_ERROR %1: Expression '%2' evaluated to %3
+This error message indicates that a problem was encountered while
+evaluating the expression of an additional client class.
A description of the problem is printed.
-% DHCP6_REQUIRED_CLASS_EVAL_RESULT %1: Expression '%2' evaluated to %3
+% DHCP6_ADDITIONAL_CLASS_EVAL_RESULT %1: Expression '%2' evaluated to %3
Logged at debug log level 50.
-This debug message indicates that the expression of a required client class has
+This debug message indicates that the expression of an additional client class has
been successfully evaluated. The client class name and the result value of the
evaluation are printed.
-% DHCP6_REQUIRED_CLASS_NO_TEST required class %1 has no test expression, adding it to client's classes unconditionally
+% DHCP6_ADDITIONAL_CLASS_NO_TEST additional class %1 has no test expression, adding it to client's classes unconditionally
Logged at debug log level 40.
-This debug message informs that a class was listed for required evaluation but
+This debug message informs that a class was listed for additional evaluation but
its definition does not include a test expression to evaluate. The class is
unconditionally added to the query.
-% DHCP6_REQUIRED_CLASS_UNDEFINED required class %1 has no definition
+% DHCP6_ADDITIONAL_CLASS_UNDEFINED additional class %1 has no definition
Logged at debug log level 40.
-This debug message informs that a class is listed for required evaluation but
+This debug message informs that a class is listed for additional evaluation but
has no definition. The class is ignored.
% DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1: %2 message received from %3 failed the following check: %4
const ClientClassDefPtr class_def = dict->findClass(cclass);
if (!class_def) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC,
- DHCP6_REQUIRED_CLASS_UNDEFINED)
+ DHCP6_ADDITIONAL_CLASS_UNDEFINED)
.arg(cclass);
// Ignore it as it can't have an attached action
continue;
// Add a class without an expression to evaluate
if (!expr_ptr) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC,
- DHCP6_REQUIRED_CLASS_NO_TEST)
+ DHCP6_ADDITIONAL_CLASS_NO_TEST)
.arg(cclass);
pkt->addClass(cclass);
continue;
// true (match) or raise an exception (error)
try {
bool status = evaluateBool(*expr_ptr, *pkt);
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_REQUIRED_CLASS_EVAL_RESULT)
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_ADDITIONAL_CLASS_EVAL_RESULT)
.arg(pkt->getLabel())
.arg(cclass)
.arg(status ? "true" : "false");
pkt->addClass(cclass);
}
} catch (const Exception& ex) {
- LOG_ERROR(dhcp6_logger, DHCP6_REQUIRED_CLASS_EVAL_ERROR)
+ LOG_ERROR(dhcp6_logger, DHCP6_ADDITIONAL_CLASS_EVAL_ERROR)
.arg(pkt->getLabel())
.arg(cclass)
.arg(ex.what());
EXPECT_FALSE(opt3);
}
-// Check that only-if-required classes are not evaluated by classifyPacket
-TEST_F(ClassifyTest, required) {
+// Check that only-in-additional-list classes are not evaluated by classifyPacket
+TEST_F(ClassifyTest, additional) {
IfaceMgrTestConfig test_config(true);
NakedDhcpv6Srv srv(0);
" \"interface\": \"eth1\" } ],"
"\"client-classes\": [ "
"{ \"name\": \"router\", "
- " \"only-if-required\": true, "
+ " \"only-in-additional-list\": true, "
" \"option-data\": ["
" { \"name\": \"ipv6-forwarding\", "
" \"data\": \"true\" } ], "
EXPECT_FALSE(opt3);
}
-// Checks that when only-if-required classes are still evaluated
-TEST_F(ClassifyTest, requiredClassification) {
+// Checks that when only-in-additional-list classes are still evaluated
+TEST_F(ClassifyTest, additionalClassification) {
IfaceMgrTestConfig test_config(true);
NakedDhcpv6Srv srv(0);
"{ \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
" \"id\": 1, "
" \"subnet\": \"2001:db8:1::/48\", "
- " \"require-client-classes\": [ \"router\" ], "
+ " \"evaluate-additional-classes\": [ \"router\" ], "
" \"interface\": \"eth1\" } ],"
"\"client-classes\": [ "
"{ \"name\": \"router\", "
- " \"only-if-required\": true, "
+ " \"only-in-additional-list\": true, "
" \"option-data\": ["
" { \"name\": \"ipv6-forwarding\", "
" \"data\": \"true\" } ], "
EXPECT_FALSE(ipf3->readBoolean());
}
-// This test checks the precedence order in required evaluation.
+// This test checks the precedence order in additional evaluation.
// This order is: pools > subnet > shared-network
TEST_F(ClassifyTest, precedenceNone) {
std::string config =
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::3\""
EXPECT_FALSE(opt);
}
-// This test checks the precedence order in required evaluation.
+// This test checks the precedence order in additional evaluation.
// This order is: pools > subnet > shared-network
TEST_F(ClassifyTest, precedencePool) {
std::string config =
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::3\""
"\"shared-networks\": [ {"
" \"name\": \"frog\","
" \"interface\": \"eth1\","
- " \"require-client-classes\": [ \"for-network\" ],"
+ " \"evaluate-additional-classes\": [ \"for-network\" ],"
" \"subnet6\": [ { "
" \"subnet\": \"2001:db8:1::/64\","
" \"id\": 1,"
- " \"require-client-classes\": [ \"for-subnet\" ],"
+ " \"evaluate-additional-classes\": [ \"for-subnet\" ],"
" \"pools\": [ { "
" \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\","
- " \"require-client-classes\": [ \"for-pool\" ]"
+ " \"evaluate-additional-classes\": [ \"for-pool\" ]"
" } ]"
" } ]"
"} ],"
EXPECT_EQ("2001:db8:1::1", addrs[0].toText());
}
-// This test checks the precedence order in required evaluation.
+// This test checks the precedence order in additional evaluation.
// This order is: pools > subnet > shared-network
TEST_F(ClassifyTest, precedencePdPool) {
std::string config =
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::3\""
"\"shared-networks\": [ {"
" \"name\": \"frog\","
" \"interface\": \"eth1\","
- " \"require-client-classes\": [ \"for-network\" ],"
+ " \"evaluate-additional-classes\": [ \"for-network\" ],"
" \"subnet6\": [ { "
" \"subnet\": \"2001:db8:1::/64\","
" \"id\": 1,"
- " \"require-client-classes\": [ \"for-subnet\" ],"
+ " \"evaluate-additional-classes\": [ \"for-subnet\" ],"
" \"pd-pools\": [ { "
" \"prefix\": \"2001:db8:1::\","
" \"prefix-len\": 48, \"delegated-len\": 64,"
- " \"require-client-classes\": [ \"for-pool\" ]"
+ " \"evaluate-additional-classes\": [ \"for-pool\" ]"
" } ]"
" } ]"
"} ],"
EXPECT_EQ("2001:db8:1::1", addrs[0].toText());
}
-// This test checks the precedence order in required evaluation.
+// This test checks the precedence order in additional evaluation.
// This order is: pools > subnet > shared-network
TEST_F(ClassifyTest, precedenceSubnet) {
std::string config =
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::3\""
"\"shared-networks\": [ {"
" \"name\": \"frog\","
" \"interface\": \"eth1\","
- " \"require-client-classes\": [ \"for-network\" ],"
+ " \"evaluate-additional-classes\": [ \"for-network\" ],"
" \"subnet6\": [ { "
" \"subnet\": \"2001:db8:1::/64\","
" \"id\": 1,"
- " \"require-client-classes\": [ \"for-subnet\" ],"
+ " \"evaluate-additional-classes\": [ \"for-subnet\" ],"
" \"pools\": [ { "
" \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
" } ]"
EXPECT_EQ("2001:db8:1::2", addrs[0].toText());
}
-// This test checks the precedence order in required evaluation.
+// This test checks the precedence order in additional evaluation.
// This order is: pools > subnet > shared-network
TEST_F(ClassifyTest, precedenceNetwork) {
std::string config =
" {"
" \"name\": \"for-pool\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::1\""
" {"
" \"name\": \"for-subnet\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::2\""
" {"
" \"name\": \"for-network\","
" \"test\": \"member('ALL')\","
- " \"only-if-required\": true,"
+ " \"only-in-additional-list\": true,"
" \"option-data\": [ {"
" \"name\": \"dns-servers\","
" \"data\": \"2001:db8:1::3\""
"\"shared-networks\": [ {"
" \"name\": \"frog\","
" \"interface\": \"eth1\","
- " \"require-client-classes\": [ \"for-network\" ],"
+ " \"evaluate-additional-classes\": [ \"for-network\" ],"
" \"subnet6\": [ { "
" \"subnet\": \"2001:db8:1::/64\","
" \"id\": 1,"
EXPECT_EQ("2001:db8:1::3", addrs[0].toText());
}
-// This test checks a required class without a test entry can be
+// This test checks a additional class without a test entry can be
// unconditionally added.
-TEST_F(ClassifyTest, requiredNoTest) {
+TEST_F(ClassifyTest, additionalNoTest) {
std::string config =
"{"
"\"interfaces-config\": {"
"\"shared-networks\": [ {"
" \"name\": \"frog\","
" \"interface\": \"eth1\","
- " \"require-client-classes\": [ \"for-network\" ],"
+ " \"evaluate-additional-classes\": [ \"for-network\" ],"
" \"subnet6\": [ { "
" \"subnet\": \"2001:db8:1::/64\","
" \"id\": 1,"
EXPECT_EQ("2001:db8:1::3", addrs[0].toText());
}
-// This test checks a required class which is not defined is ignored.
+// This test checks a additional class which is not defined is ignored.
// Please set KEA_LOGGER_DESTINATION to stderr or stdout and check
// that DHCP6_REQUIRED_CLASS_UNDEFINED is logged,
-TEST_F(ClassifyTest, requiredNotDefined) {
+TEST_F(ClassifyTest, additionalNotDefined) {
std::string config =
"{"
"\"interfaces-config\": {"
"\"shared-networks\": [ {"
" \"name\": \"frog\","
" \"interface\": \"eth1\","
- " \"require-client-classes\": [ \"for-network\" ],"
+ " \"evaluate-additional-classes\": [ \"for-network\" ],"
" \"subnet6\": [ { "
" \"subnet\": \"2001:db8:1::/64\","
" \"id\": 1,"
R"^(
"rebind-timer": 2000,
"renew-timer": 1000,
- "subnet6": [{
- "require-client-classes": [ "foo" ],
- "pools": [{ "pool": "2001:db8::/64" }],
- "id": 1,
- "subnet": "2001:db8::/64"
+ "shared-networks":[{
+ "name": "net1",
+ "require-client-classes": [ "one" ],
+ "subnet6": [{
+ "require-client-classes": [ "two" ],
+ "pools": [{
+ "pool": "2001:db8::/64",
+ "require-client-classes": [ "three" ],
+ }],
+ "pd-pools": [{
+ "prefix": "3001:db8::",
+ "prefix-len": 56,
+ "delegated-len": 64,
+ "require-client-classes": [ "four" ],
+ }],
+ "id": 1,
+ "subnet": "2001:db8::/64"
+ }],
}],
"valid-lifetime": 400
})^";
ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
checkResult(status, 0);
+ SharedNetwork6Ptr network = CfgMgr::instance().getStagingCfg()->
+ getCfgSharedNetworks6()->getByName("net1");
+ ASSERT_TRUE(network);
+
+ auto& net_class_list = network->getAdditionalClasses();
+ EXPECT_EQ(1, net_class_list.size());
+ auto cclasses = net_class_list.begin();
+ EXPECT_EQ(*cclasses, "one");
+
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets6()->selectSubnet(IOAddress("2001:db8::"));
ASSERT_TRUE(subnet);
- const auto& cclass_list = subnet->getAdditionalClasses();
- EXPECT_EQ(1, cclass_list.size());
- auto cclasses = cclass_list.begin();
- EXPECT_EQ(*cclasses, "foo");
+ const auto& sub_class_list = subnet->getAdditionalClasses();
+ EXPECT_EQ(1, sub_class_list.size());
+ cclasses = sub_class_list.begin();
+ EXPECT_EQ(*cclasses, "two");
+
+ PoolPtr pool = subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8::"), false);
+ ASSERT_TRUE(pool);
+
+ auto& pool_class_list = pool->getAdditionalClasses();
+ EXPECT_EQ(1, pool_class_list.size());
+ cclasses = pool_class_list.begin();
+ EXPECT_EQ(*cclasses, "three");
+
+ pool = subnet->getPool(Lease::TYPE_PD, IOAddress("3001:db8::"), false);
+ ASSERT_TRUE(pool);
+
+ auto& pd_pool_class_list = pool->getAdditionalClasses();
+ EXPECT_EQ(1, pd_pool_class_list.size());
+ cclasses = pd_pool_class_list.begin();
+ EXPECT_EQ(*cclasses, "four");
// Now verify that users cannot specify both.
config = "{ " + genIfaceConfig() + ","
}
TEST_F(ClientClassDefParserTest, deprecatedOnlyIfRequired) {
- // Valid entry.
+ // Valid entry using only-if-required.
std::string cfg_text =
R"^({
"name": "foo",
EXPECT_EQ("foo", cclass->getName());
ASSERT_TRUE(cclass->getAdditional());
+ // Valid entry using only-in-additional-list.
+ cfg_text =
+ R"^({
+ "name": "foo",
+ "only-in-additional-list": true
+ })^";
+
+ ASSERT_NO_THROW(cclass = parseClientClassDef(cfg_text, AF_INET));
+
+ // Class should exist.
+ ASSERT_TRUE(cclass);
+ EXPECT_EQ("foo", cclass->getName());
+ ASSERT_TRUE(cclass->getAdditional());
+
// Invalid entry specifies both parameters.
std::string cfg_text2 =
R"^({
" \"client-classes\": [",
" {",
" \"name\": <name of the class>,",
- " \"only-if-required\": <only if required boolean value>,",
+ " \"only-in-additional-list\": <only in additional list boolean value>,",
" \"test\": <test expression to be evaluated on incoming packets>,",
" \"option-data\": [ <option values here> ],",
" \"option-def\": [ <option definitions here> ],",