diff options
-rw-r--r-- | doc/examples/kea4/all-keys-netconf.json | 41 | ||||
-rw-r--r-- | doc/examples/kea4/all-keys.json | 41 | ||||
-rw-r--r-- | doc/examples/kea4/global-reservations.json | 11 | ||||
-rw-r--r-- | doc/examples/kea4/reservations.json | 12 | ||||
-rw-r--r-- | doc/examples/kea4/shared-network.json | 31 | ||||
-rw-r--r-- | doc/examples/kea6/all-keys-netconf.json | 39 | ||||
-rw-r--r-- | doc/examples/kea6/all-keys.json | 39 | ||||
-rw-r--r-- | doc/examples/kea6/global-reservations.json | 13 | ||||
-rw-r--r-- | doc/examples/kea6/reservations.json | 11 | ||||
-rw-r--r-- | doc/examples/kea6/shared-network.json | 31 | ||||
-rw-r--r-- | doc/sphinx/arm/dhcp4-srv.rst | 100 | ||||
-rw-r--r-- | doc/sphinx/arm/dhcp6-srv.rst | 101 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_lexer.ll | 13 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_parser.yy | 53 | ||||
-rw-r--r-- | src/bin/dhcp4/parser_context.h | 6 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_lexer.ll | 13 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_parser.yy | 56 | ||||
-rw-r--r-- | src/bin/dhcp6/parser_context.h | 6 | ||||
-rw-r--r-- | src/lib/dhcpsrv/alloc_engine.cc | 26 | ||||
-rw-r--r-- | src/lib/dhcpsrv/network.h | 14 |
20 files changed, 600 insertions, 57 deletions
diff --git a/doc/examples/kea4/all-keys-netconf.json b/doc/examples/kea4/all-keys-netconf.json index 5cc9bff32d..9ab0f99951 100644 --- a/doc/examples/kea4/all-keys-netconf.json +++ b/doc/examples/kea4/all-keys-netconf.json @@ -563,7 +563,16 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // List of client classes which must be evaluated when this shared // network is selected for client assignments. @@ -685,9 +694,18 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", - // Subnet-level compute T1 and T2 timers. + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, + + // Subnet level compute T1 and T2 timers. "calculate-tee-times": true, // T1 = valid lifetime * .5. @@ -772,8 +790,7 @@ // Configuration control (currently not used, i.e. this syntax // is already defined but corresponding feature is not implemented). - "config-control": - { + "config-control": { // Only configuration databases entry is defined. "config-databases": [ { @@ -793,8 +810,7 @@ "server-tag": "my DHCPv4 server", // DHCP queue control parameters. - "dhcp-queue-control": - { + "dhcp-queue-control": { // Enable queue is mandatory. "enable-queue": true, @@ -803,7 +819,16 @@ }, // Fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // Global compute T1 and T2 timers. "calculate-tee-times": true, diff --git a/doc/examples/kea4/all-keys.json b/doc/examples/kea4/all-keys.json index a8aedd94b4..3a75c3259c 100644 --- a/doc/examples/kea4/all-keys.json +++ b/doc/examples/kea4/all-keys.json @@ -695,7 +695,16 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // List of client classes which must be evaluated when this shared // network is selected for client assignments. @@ -858,9 +867,18 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", - // Subnet-level compute T1 and T2 timers. + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, + + // Subnet level compute T1 and T2 timers. "calculate-tee-times": true, // T1 = valid lifetime * .5. @@ -954,8 +972,7 @@ // Configuration control (currently not used, i.e. this syntax // is already defined but corresponding feature is not implemented). - "config-control": - { + "config-control": { // Only configuration databases entry is defined. "config-databases": [ { @@ -975,8 +992,7 @@ "server-tag": "my DHCPv4 server", // DHCP queue control parameters. - "dhcp-queue-control": - { + "dhcp-queue-control": { // Enable queue is mandatory. "enable-queue": true, @@ -988,7 +1004,16 @@ }, // Fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // Global compute T1 and T2 timers. "calculate-tee-times": true, diff --git a/doc/examples/kea4/global-reservations.json b/doc/examples/kea4/global-reservations.json index 155b56aeea..d5bb5ef9f8 100644 --- a/doc/examples/kea4/global-reservations.json +++ b/doc/examples/kea4/global-reservations.json @@ -51,7 +51,16 @@ // This directive tells Kea that reservations are global. Note that this // can also be specified at shared network and/or subnet level. - "reservation-mode": "global", +// It is deprecated by the "reservation-modes" map. +// "reservation-mode": "global", + +// Since Kea 1.9.1, a more flexible option of configuring the way Kea uses host +// reservations is available through the 'reservation-modes' map. + "reservation-modes": { + "global": True, + "in-subnet": False, + "out-of-pool": False + }, // Define several global host reservations. "reservations": [ diff --git a/doc/examples/kea4/reservations.json b/doc/examples/kea4/reservations.json index 61b18bd8b4..4f1864f805 100644 --- a/doc/examples/kea4/reservations.json +++ b/doc/examples/kea4/reservations.json @@ -66,7 +66,17 @@ // out of the dynamic pool and change reservation-mode to "out-of-pool". // Kea will then be able to skip querying for host reservations when // assigning leases from dynamic pool. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, + "reservations": [ // This is a reservation for a specific hardware/MAC address. It's a very diff --git a/doc/examples/kea4/shared-network.json b/doc/examples/kea4/shared-network.json index 397869fd6e..08c3bf2bfa 100644 --- a/doc/examples/kea4/shared-network.json +++ b/doc/examples/kea4/shared-network.json @@ -64,7 +64,16 @@ // Timer values can be overridden here. "renew-timer": 100, - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // This starts a list of subnets allowed in this shared network. // In our example, there are two subnets. @@ -86,7 +95,15 @@ "ip-address": "0.0.0.0" }, "renew-timer": 10, - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, "subnet": "10.0.0.0/8", "valid-lifetime": 30 }, @@ -100,7 +117,15 @@ "pools": [ ], "rebind-timer": 20, "renew-timer": 10, - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, "subnet": "192.0.2.0/24", "valid-lifetime": 30 } diff --git a/doc/examples/kea6/all-keys-netconf.json b/doc/examples/kea6/all-keys-netconf.json index eb16357c2e..7585399fb6 100644 --- a/doc/examples/kea6/all-keys-netconf.json +++ b/doc/examples/kea6/all-keys-netconf.json @@ -528,7 +528,16 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // List of client classes which must be evaluated when this shared // network is selected for client assignments. @@ -676,7 +685,16 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // Subnet level compute T1 and T2 timers. "calculate-tee-times": true, @@ -763,8 +781,7 @@ // Configuration control (currently not used, i.e. this syntax // is already defined but corresponding feature is not implemented). - "config-control": - { + "config-control": { // Only configuration databases entry is defined. "config-databases": [ { @@ -784,8 +801,7 @@ "server-tag": "my DHCPv6 server", // DHCP queue control parameters. - "dhcp-queue-control": - { + "dhcp-queue-control": { // Enable queue is mandatory. "enable-queue": true, @@ -794,7 +810,16 @@ }, // Fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // Data directory. "data-directory": "/tmp", diff --git a/doc/examples/kea6/all-keys.json b/doc/examples/kea6/all-keys.json index ab84a84351..9482db7521 100644 --- a/doc/examples/kea6/all-keys.json +++ b/doc/examples/kea6/all-keys.json @@ -653,7 +653,16 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // List of client classes which must be evaluated when this shared // network is selected for client assignments. @@ -839,7 +848,16 @@ // Enumeration specifying server's mode of operation when it // fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // Subnet level compute T1 and T2 timers. "calculate-tee-times": true, @@ -932,8 +950,7 @@ // Configuration control (currently not used, i.e. this syntax // is already defined but corresponding feature is not implemented). - "config-control": - { + "config-control": { // Only configuration databases entry is defined. "config-databases": [ { @@ -953,8 +970,7 @@ "server-tag": "my DHCPv6 server", // DHCP queue control parameters. - "dhcp-queue-control": - { + "dhcp-queue-control": { // Enable queue is mandatory. "enable-queue": true, @@ -966,7 +982,16 @@ }, // Fetches host reservations. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // Data directory. "data-directory": "/tmp", diff --git a/doc/examples/kea6/global-reservations.json b/doc/examples/kea6/global-reservations.json index b5674178c1..53e253a8d9 100644 --- a/doc/examples/kea6/global-reservations.json +++ b/doc/examples/kea6/global-reservations.json @@ -36,11 +36,20 @@ // costly database lookup to do so. It is therefore useful from a performance // perspective to use only the reservation types that are actually used in a // given network. - "host-reservation-identifiers": [ "duid", "hw-address", "flex-id" ], + "host-reservation-identifiers": [ "duid", "hw-address", "flex-id" ], // This directive tells Kea that reservations are global. Note that this // can also be specified at shared network and/or subnet level. - "reservation-mode": "global", +// It is deprecated by the "reservation-modes" map. +// "reservation-mode": "global", + +// Since Kea 1.9.1, a more flexible option of configuring the way Kea uses host +// reservations is available through the 'reservation-modes' map. + "reservation-modes": { + "global": True, + "in-subnet": False, + "out-of-pool": False + }, // Define several global host reservations. "reservations": [ diff --git a/doc/examples/kea6/reservations.json b/doc/examples/kea6/reservations.json index dad59d4f1e..5005b5100e 100644 --- a/doc/examples/kea6/reservations.json +++ b/doc/examples/kea6/reservations.json @@ -48,7 +48,16 @@ // out of the dynamic pool and change reservation-mode to "out-of-pool". // Kea will then be able to skip querying for host reservations when // assigning leases from dynamic pool. - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, "pools": [ { "pool": "2001:db8:1::/120" } ], diff --git a/doc/examples/kea6/shared-network.json b/doc/examples/kea6/shared-network.json index a8a537e36f..49f1c998ea 100644 --- a/doc/examples/kea6/shared-network.json +++ b/doc/examples/kea6/shared-network.json @@ -69,7 +69,16 @@ "ip-address": "2001:db8::1" }, "renew-timer": 100, - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, // List of subnets belonging to this particular shared-network // start here. @@ -85,7 +94,15 @@ "ip-address": "2001:db8:1::123" }, "renew-timer": 10, - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, "subnet": "2001:db8:1::/64", "pools": [ { "pool": "2001:db8:1:abcd::/64" } ], "valid-lifetime": 40 @@ -101,7 +118,15 @@ "ip-address": "3000::1" }, "renew-timer": 10, - "reservation-mode": "all", + // It is deprecated by the "reservation-modes" map. + // "reservation-mode": "all", + // Reservation modes specifying server's mode of operation when it + // fetches host reservations. + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, "subnet": "3000::/16", "valid-lifetime": 40 } diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst index 1fde30bc7e..fde29ba960 100644 --- a/doc/sphinx/arm/dhcp4-srv.rst +++ b/doc/sphinx/arm/dhcp4-srv.rst @@ -4621,6 +4621,106 @@ An example configuration using global reservations is shown below: ] } +Since Kea 1.9.1, the ``reservation-mode`` is deprecated by the +``reservation-modes`` map. +The map contains ``global``, ``in-subnet`` and ``out-of-pool`` boolean flags. +The flags can be activated independently and can produce various combinations, +some of them being unsuported by the deprecated ``reservation-mode``. + +The correspondence of old values are: + +``disabled``: + + "reservation-modes": { + "global": False, + "in-subnet": False, + "out-of-pool": False + }, + +``global``: + + "reservation-modes": { + "global": True, + "in-subnet": False, + "out-of-pool": False + }, + +``out-of-pool``: + + "reservation-modes": { + "global": False, + "in-subnet": False, + "out-of-pool": True + }, + +``all``: + + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, + +To activate both ``global`` and ``all``, the following combination can be used: + + "reservation-modes": { + "global": True, + "in-subnet": True, + "out-of-pool": True + }, + +The parameter can be specified at global, subnet, and shared-network +levels. + +An example configuration that disables reservation looks as follows: + +:: + + "Dhcp4": { + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "reservation-modes": { + "global": False, + "in-subnet": False, + "out-of-pool": False + }, + ... + } + ] + } + +An example configuration using global reservations is shown below: + +:: + + "Dhcp4": { + + + "reservation-modes": { + "global": True, + "in-subnet": False, + "out-of-pool": False + }, + "reservations": [ + { + "hw-address": "01:bb:cc:dd:ee:ff", + "hostname": "host-one" + }, + { + "hw-address": "02:bb:cc:dd:ee:ff", + "hostname": "host-two" + } + ], + + "subnet4": [ + { + "subnet": "192.0.2.0/24", + ... + } + ] + } + For more details regarding global reservations, see :ref:`global-reservations4`. Another aspect of host reservations is the different types of diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst index 9fa897fdaa..a9500e47b9 100644 --- a/doc/sphinx/arm/dhcp6-srv.rst +++ b/doc/sphinx/arm/dhcp6-srv.rst @@ -4067,6 +4067,107 @@ An example configuration using global reservations is shown below: ] } +Since Kea 1.9.1, the ``reservation-mode`` is deprecated by the +``reservation-modes`` map. +The map contains ``global``, ``in-subnet`` and ``out-of-pool`` boolean flags. +The flags can be activated independently and can produce various combinations, +some of them being unsuported by the deprecated ``reservation-mode``. + +The correspondence of old values are: + +``disabled``: + + "reservation-modes": { + "global": False, + "in-subnet": False, + "out-of-pool": False + }, + +``global``: + + "reservation-modes": { + "global": True, + "in-subnet": False, + "out-of-pool": False + }, + +``out-of-pool``: + + "reservation-modes": { + "global": False, + "in-subnet": False, + "out-of-pool": True + }, + +``all``: + + "reservation-modes": { + "global": False, + "in-subnet": True, + "out-of-pool": True + }, + +To activate both ``global`` and ``all``, the following combination can be used: + + "reservation-modes": { + "global": True, + "in-subnet": True, + "out-of-pool": True + }, + +The parameter can be specified at global, subnet, and shared-network +levels. + +An example configuration that disables reservation looks as follows: + +:: + + "Dhcp6": { + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "reservation-modes": { + "global": False, + "in-subnet": False, + "out-of-pool": False + }, + ... + } + ] + } + + +An example configuration using global reservations is shown below: + +:: + + "Dhcp6": { + + + "reservation-modes": { + "global": True, + "in-subnet": False, + "out-of-pool": False + }, + "reservations": [ + { + "duid": "00:03:00:01:11:22:33:44:55:66", + "hostname": "host-one" + }, + { + "duid": "00:03:00:01:99:88:77:66:55:44", + "hostname": "host-two" + } + ], + + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + ... + } + ] + } + For more details regarding global reservations, see :ref:`global-reservations6`. Another aspect of host reservations is the different types of diff --git a/src/bin/dhcp4/dhcp4_lexer.ll b/src/bin/dhcp4/dhcp4_lexer.ll index e1b1f1ba32..26917e509b 100644 --- a/src/bin/dhcp4/dhcp4_lexer.ll +++ b/src/bin/dhcp4/dhcp4_lexer.ll @@ -136,6 +136,8 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] return isc::dhcp::Dhcp4Parser::make_SUB_HOOKS_LIBRARY(driver.loc_); case Parser4Context::PARSER_DHCP_DDNS: return isc::dhcp::Dhcp4Parser::make_SUB_DHCP_DDNS(driver.loc_); + case Parser4Context::PARSER_RESERVATION_MODES: + return isc::dhcp::Dhcp4Parser::make_SUB_RESERVATION_MODES(driver.loc_); case Parser4Context::PARSER_CONFIG_CONTROL: return isc::dhcp::Dhcp4Parser::make_SUB_CONFIG_CONTROL(driver.loc_); } @@ -959,6 +961,17 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] } } +\"reservation-modes\" { + switch(driver.ctx_) { + case isc::dhcp::Parser4Context::DHCP4: + case isc::dhcp::Parser4Context::SUBNET4: + case isc::dhcp::Parser4Context::SHARED_NETWORK: + return isc::dhcp::Dhcp4Parser::make_RESERVATION_MODES(driver.loc_); + default: + return isc::dhcp::Dhcp4Parser::make_STRING("reservation-modes", driver.loc_); + } +} + \"disabled\" { switch(driver.ctx_) { case isc::dhcp::Parser4Context::RESERVATION_MODE: diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 9e27bf6005..ccd9605b89 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -152,10 +152,14 @@ using namespace std; INTERFACE "interface" ID "id" RESERVATION_MODE "reservation-mode" + RESERVATION_MODES "reservation-modes" DISABLED "disabled" OUT_OF_POOL "out-of-pool" GLOBAL "global" ALL "all" + HR_GLOBAL "global" + HR_IN_SUBNET "in-subnet" + HR_OUT_OF_POOL "out-of-pool" HOST_RESERVATION_IDENTIFIERS "host-reservation-identifiers" @@ -253,6 +257,7 @@ using namespace std; SUB_OPTION_DATA SUB_HOOKS_LIBRARY SUB_DHCP_DDNS + SUB_RESERVATION_MODES SUB_CONFIG_CONTROL ; @@ -291,6 +296,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns + | SUB_RESERVATION_MODES { ctx.ctx_ = ctx.RESERVATION_MODES; } sub_reservation_modes | SUB_CONFIG_CONTROL { ctx.ctx_ = ctx.CONFIG_CONTROL; } sub_config_control ; @@ -1477,6 +1483,53 @@ hr_mode: DISABLED { $$ = ElementPtr(new StringElement("disabled", ctx.loc2pos(@1 | ALL { $$ = ElementPtr(new StringElement("all", ctx.loc2pos(@1))); } ; +reservation_modes: RESERVATION_MODES { + ctx.unique("reservation-modes", ctx.loc2pos(@1)); + ElementPtr m(new MapElement(ctx.loc2pos(@1))); + ctx.stack_.back()->set("reservation-modes", m); + ctx.stack_.push_back(m); + ctx.enter(ctx.RESERVATION_MODES); +} COLON LCURLY_BRACKET reservation_modes_params RCURLY_BRACKET { + ctx.stack_.pop_back(); + ctx.leave(); +}; + +sub_reservation_modes: LCURLY_BRACKET { + // Parse the reservation-modes map + ElementPtr m(new MapElement(ctx.loc2pos(@1))); + ctx.stack_.push_back(m); +} reservation_modes_params RCURLY_BRACKET { + // No config_control params are required + // parsing completed +}; + +reservation_modes_params: reservation_modes_param + | reservation_modes_params COMMA reservation_modes_param + ; + +reservation_modes_param: hr_global + | hr_in_subnet + | hr_out_of_pool + ; + +hr_global: HR_GLOBAL COLON BOOLEAN { + ctx.unique("global", ctx.loc2pos(@1)); + ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("global", b); +}; + +hr_in_subnet: HR_IN_SUBNET COLON BOOLEAN { + ctx.unique("in-subnet", ctx.loc2pos(@1)); + ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("in-subnet", b); +}; + +hr_out_of_pool: HR_OUT_OF_POOL COLON BOOLEAN { + ctx.unique("out-of-pool", ctx.loc2pos(@1)); + ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("out-of-pool", b); +}; + id: ID COLON INTEGER { ctx.unique("id", ctx.loc2pos(@1)); ElementPtr id(new IntElement($3, ctx.loc2pos(@3))); diff --git a/src/bin/dhcp4/parser_context.h b/src/bin/dhcp4/parser_context.h index e87f4732e7..0bf2e7b40a 100644 --- a/src/bin/dhcp4/parser_context.h +++ b/src/bin/dhcp4/parser_context.h @@ -87,6 +87,9 @@ public: /// This will parse the input as dhcp-ddns. PARSER_DHCP_DDNS, + /// This will parse the input as reservation-modes. + PARSER_RESERVATION_MODES, + /// This will parse the input as config-control. PARSER_CONFIG_CONTROL, } ParserType; @@ -314,6 +317,9 @@ public: /// Used while parsing Dhcp4/config-control CONFIG_CONTROL, + /// Used while parsing Dhcp4/reservation-modes + RESERVATION_MODES, + /// Used while parsing config-control/config-databases CONFIG_DATABASE diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 99b61cb0b3..a464814cfa 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -138,6 +138,8 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] return isc::dhcp::Dhcp6Parser::make_SUB_HOOKS_LIBRARY(driver.loc_); case Parser6Context::PARSER_DHCP_DDNS: return isc::dhcp::Dhcp6Parser::make_SUB_DHCP_DDNS(driver.loc_); + case Parser6Context::PARSER_RESERVATION_MODES: + return isc::dhcp::Dhcp6Parser::make_SUB_RESERVATION_MODES(driver.loc_); case Parser6Context::PARSER_CONFIG_CONTROL: return isc::dhcp::Dhcp6Parser::make_SUB_CONFIG_CONTROL(driver.loc_); } @@ -1269,6 +1271,17 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] } } +\"reservation-modes\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::SHARED_NETWORK: + return isc::dhcp::Dhcp6Parser::make_RESERVATION_MODES(driver.loc_); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reservation-modes", driver.loc_); + } +} + \"disabled\" { switch(driver.ctx_) { case isc::dhcp::Parser6Context::RESERVATION_MODE: diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index e0fe398404..e4a457d7ac 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -126,6 +126,8 @@ using namespace std; ENCAPSULATE "encapsulate" ARRAY "array" + SHARED_NETWORKS "shared-networks" + POOLS "pools" POOL "pool" PD_POOLS "pd-pools" @@ -143,11 +145,14 @@ using namespace std; ID "id" RAPID_COMMIT "rapid-commit" RESERVATION_MODE "reservation-mode" + RESERVATION_MODES "reservation-modes" DISABLED "disabled" OUT_OF_POOL "out-of-pool" GLOBAL "global" ALL "all" - SHARED_NETWORKS "shared-networks" + HR_GLOBAL "global" + HR_IN_SUBNET "in-subnet" + HR_OUT_OF_POOL "out-of-pool" MAC_SOURCES "mac-sources" RELAY_SUPPLIED_OPTIONS "relay-supplied-options" @@ -260,6 +265,7 @@ using namespace std; SUB_OPTION_DATA SUB_HOOKS_LIBRARY SUB_DHCP_DDNS + SUB_RESERVATION_MODES SUB_CONFIG_CONTROL ; @@ -298,6 +304,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns + | SUB_RESERVATION_MODES { ctx.ctx_ = ctx.RESERVATION_MODES; } sub_reservation_modes | SUB_CONFIG_CONTROL { ctx.ctx_ = ctx.CONFIG_CONTROL; } sub_config_control ; @@ -1469,6 +1476,53 @@ hr_mode: DISABLED { $$ = ElementPtr(new StringElement("disabled", ctx.loc2pos(@1 | ALL { $$ = ElementPtr(new StringElement("all", ctx.loc2pos(@1))); } ; +reservation_modes: RESERVATION_MODES { + ctx.unique("reservation-modes", ctx.loc2pos(@1)); + ElementPtr m(new MapElement(ctx.loc2pos(@1))); + ctx.stack_.back()->set("reservation-modes", m); + ctx.stack_.push_back(m); + ctx.enter(ctx.RESERVATION_MODES); +} COLON LCURLY_BRACKET reservation_modes_params RCURLY_BRACKET { + ctx.stack_.pop_back(); + ctx.leave(); +}; + +sub_reservation_modes: LCURLY_BRACKET { + // Parse the reservation-modes map + ElementPtr m(new MapElement(ctx.loc2pos(@1))); + ctx.stack_.push_back(m); +} reservation_modes_params RCURLY_BRACKET { + // No config_control params are required + // parsing completed +}; + +reservation_modes_params: reservation_modes_param + | reservation_modes_params COMMA reservation_modes_param + ; + +reservation_modes_param: hr_global + | hr_in_subnet + | hr_out_of_pool + ; + +hr_global: HR_GLOBAL COLON BOOLEAN { + ctx.unique("global", ctx.loc2pos(@1)); + ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("global", b); +}; + +hr_in_subnet: HR_IN_SUBNET COLON BOOLEAN { + ctx.unique("in-subnet", ctx.loc2pos(@1)); + ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("in-subnet", b); +}; + +hr_out_of_pool: HR_OUT_OF_POOL COLON BOOLEAN { + ctx.unique("out-of-pool", ctx.loc2pos(@1)); + ElementPtr b(new BoolElement($3, ctx.loc2pos(@3))); + ctx.stack_.back()->set("out-of-pool", b); +}; + id: ID COLON INTEGER { ctx.unique("id", ctx.loc2pos(@1)); ElementPtr id(new IntElement($3, ctx.loc2pos(@3))); diff --git a/src/bin/dhcp6/parser_context.h b/src/bin/dhcp6/parser_context.h index e95b12949e..cdc2da5329 100644 --- a/src/bin/dhcp6/parser_context.h +++ b/src/bin/dhcp6/parser_context.h @@ -90,6 +90,9 @@ public: /// This will parse the input as dhcp-ddns. (D2 client config) PARSER_DHCP_DDNS, + /// This will parse the input as reservation-modes. + PARSER_RESERVATION_MODES, + /// This will parse the input as config-control. PARSER_CONFIG_CONTROL, } ParserType; @@ -320,6 +323,9 @@ public: /// Used while parsing Dhcp6/config-control CONFIG_CONTROL, + /// Used while parsing Dhcp6/reservation-modes + RESERVATION_MODES, + /// Used while parsing config-control/config-databases CONFIG_DATABASE diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index c01100a92b..6ea19bb024 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -2950,8 +2950,8 @@ namespace { bool addressReserved(const IOAddress& address, const AllocEngine::ClientContext4& ctx) { if (ctx.subnet_ && - ((ctx.subnet_->getHostReservationMode() == Network::HR_ALL) || - ((ctx.subnet_->getHostReservationMode() == Network::HR_OUT_OF_POOL) && + ((ctx.subnet_->getHostReservationMode() & Network::HR_IN_SUBNET) || + ((ctx.subnet_->getHostReservationMode() & Network::HR_OUT_OF_POOL) && (!ctx.subnet_->inPool(Lease::TYPE_V4, address))))) { // The global parameter ip-reservations-unique controls whether it is allowed // to specify multiple reservations for the same IP address or delegated prefix @@ -2974,12 +2974,11 @@ addressReserved(const IOAddress& address, const AllocEngine::ClientContext4& ctx } for (auto host : hosts) { - for (auto id = ctx.host_identifiers_.cbegin(); id != ctx.host_identifiers_.cend(); - ++id) { + for (auto id : ctx.host_identifiers_) { // If we find the matching host we know that this address is reserved // for us and we can return immediatelly. - if (id->first == host->getIdentifierType() && - id->second == host->getIdentifier()) { + if (id.first == host->getIdentifierType() && + id.second == host->getIdentifier()) { return (false); } } @@ -3015,19 +3014,26 @@ hasAddressReservation(AllocEngine::ClientContext4& ctx) { Subnet4Ptr subnet = ctx.subnet_; while (subnet) { - if (subnet->getHostReservationMode() == Network::HR_GLOBAL) { + if (subnet->getHostReservationMode() & Network::HR_GLOBAL) { auto host = ctx.hosts_.find(SUBNET_ID_GLOBAL); - return (host != ctx.hosts_.end() && + bool found = (host != ctx.hosts_.end() && !(host->second->getIPv4Reservation().isV4Zero())); // if we want global + other modes we would need to // return only if true, else continue + if (subnet->getHostReservationMode() == Network::HR_GLOBAL) { + return (found); + } else { + if (found) { + return (found); + } + } } auto host = ctx.hosts_.find(subnet->getID()); if ((host != ctx.hosts_.end()) && !(host->second->getIPv4Reservation().isV4Zero()) && - ((subnet->getHostReservationMode() == Network::HR_ALL) || - ((subnet->getHostReservationMode() == Network::HR_OUT_OF_POOL) && + ((subnet->getHostReservationMode() & Network::HR_IN_SUBNET) || + ((subnet->getHostReservationMode() & Network::HR_OUT_OF_POOL) && (!subnet->inPool(Lease::TYPE_V4, host->second->getIPv4Reservation()))))) { ctx.subnet_ = subnet; return (true); diff --git a/src/lib/dhcpsrv/network.h b/src/lib/dhcpsrv/network.h index 325b61e688..89a6951fe3 100644 --- a/src/lib/dhcpsrv/network.h +++ b/src/lib/dhcpsrv/network.h @@ -159,24 +159,28 @@ public: /// None - host reservation is disabled. No reservation types /// are allowed. - HR_DISABLED, + HR_DISABLED = 0, /// Only out-of-pool reservations is allowed. This mode /// allows AllocEngine to skip reservation checks when /// dealing with with addresses that are in pool. - HR_OUT_OF_POOL, + /// When HR_IN_SUBNET is set, this is always enabled as well. + HR_OUT_OF_POOL = 1 << 0, + + /// The in-pool reservations is allowed. This mode actually + /// behaves as if out-of-pool reservations are active as well. + HR_IN_SUBNET = 1 << 1, /// Only global reservations are allowed. This mode /// instructs AllocEngine to only look at global reservations. - HR_GLOBAL, + HR_GLOBAL = 1 << 2, /// Both out-of-pool and in-pool reservations are allowed. This is the /// most flexible mode, where sysadmin have biggest liberty. However, /// there is a non-trivial performance penalty for it, as the /// AllocEngine code has to check whether there are reservations, even /// when dealing with reservations from within the dynamic pools. - /// @todo - should ALL include global? - HR_ALL + HR_ALL = HR_IN_SUBNET | HR_OUT_OF_POOL } HRMode; /// @brief Inheritance "mode" used when fetching an optional @c Network |