Browse Source

[master] Merge branch 'trac5395'

Marcin Siodelski 7 years ago
parent
commit
aceafa67f4

+ 69 - 18
doc/guide/hooks.xml

@@ -847,7 +847,7 @@ Administrator deleted a lease for a device identified by: duid of 1a:1b:1c:1d:1e
           value derived from flexible identifier. The server processes the client's
           query as if flexible identifier was sent in the client identifier (or DUID)
           option. This guarantees that returning client (for which the same flexible
-          identifier is evaluated) will be assigned the same lease desplite the client
+          identifier is evaluated) will be assigned the same lease despite the client
           identifier and/or MAC address change.
         </para>
 
@@ -870,6 +870,12 @@ Administrator deleted a lease for a device identified by: duid of 1a:1b:1c:1d:1e
         </para>
 
         <para>
+          In the DHCPv4 case, the value derived from the flexible identifier is formed
+          by prepending 1 byte with a value of zero to flexible identifier. In the IPv6
+          case, it is formed by prepanding two zero bytes before the flexible identifier.
+        </para>
+
+        <para>
           Note that for this mechanism to take effect, the DHCPv4 server must be configured
           to respect the client identifier option value during lease allocation, i.e.
           "match-client-id" must be set to true. See
@@ -882,6 +888,41 @@ Administrator deleted a lease for a device identified by: duid of 1a:1b:1c:1d:1e
           not) is ignored.
         </para>
 
+        <para>
+          The <xref linkend="lease-cmds"/> section describes commands used to retrieve,
+          update and delete leases using various identifiers, e.g. "hw-address",
+          "client-id". The lease_cmds library doesn't natively support querying for
+          leases by flexible identifier. However, when "replace-client-id" is set to
+          true, it makes it possible to query for leases using a value derived from
+          the flexible identifier. In the DHCPv4 case, the query will look similar to this:
+<screen>
+{
+    "command": "lease4-get",
+    "arguments": {
+        "identifier-type": "client-id",
+        "identifier": "00:<userinput>54:64:45:66</userinput>",
+        "subnet-id": 44
+    }
+}
+</screen>
+
+            where hexadecimal value of "54:64:45:66" is a flexible identifier computed
+            for the client.
+        </para>
+
+        <para>
+          In the DHCPv6 case, the corresponding query will look similar to this:
+<screen>
+{
+    "command": "lease6-get",
+    "arguments": {
+        "identifier-type": "duid",
+        "identifier": "00:00:<userinput>54:64:45:66</userinput>",
+        "subnet-id": 10
+    }
+}</screen>
+
+        </para>
       </section>
 
       <section id="host-cmds">
@@ -951,7 +992,7 @@ Requirements </ulink> document.</para>
         <section>
           <title>reservation-add command</title>
         <para>
-          <command>reservation-add</command> allows insertion of a new host.  It
+          <command>reservation-add</command> allows for the insertion of a new host.  It
           takes a set of arguments that vary depending on the nature of the host
           reservation. Any parameters allowed in the configuration file that
           pertain to host reservation are permitted here. For details regarding
@@ -1284,7 +1325,7 @@ An example deletion by (subnet-id, identifier-type, identifier) looks as follows
           <title>lease4-add, lease6-add commands</title>
         <para>
           <command>lease4-add</command> and <command>lease6-add</command>
-          commands allow creation of a new lease. Typically Kea creates a lease
+          commands allow for the creation of a new lease. Typically Kea creates a lease
           on its own, when it first sees a new device. However, sometimes it may
           be convenient to create the lease administratively. The
           <command>lease4-add</command> command requires at least three
@@ -1438,13 +1479,9 @@ The commands can take a number of additional optional parameters:
           used when the address (either IPv4 or IPv6) is known, but the details
           of the lease aren't. One common use case of this type of query is to
           find out whether a given address is being used or not. The second
-          query uses identifiers. For maximum flexibility, Kea stores the host
-          identifying information as a pair of values: type and the actual
-          identifier. Currently supported identifiers are "hw-address", "duid",
-          "circuit-id", "client-id" and "flex-id", but additional types may be
-          added in the future. If any new identifier types are defined in the
-          future, reservation-get command will support them
-          automatically.</para>
+          query uses identifiers. Currently supported identifiers for leases are:
+          "hw-address" (IPv4 only), "client-id" (IPv4 only) and "duid" (IPv6 only).
+          </para>
 
           <para>
             An example <command>lease4-get</command> command for getting a lease
@@ -1471,8 +1508,8 @@ The commands can take a number of additional optional parameters:
 }</screen>
           </para>
 
-          <para>An example query by (subnet-id, identifier-type,
-          identifier) for IPv4 lease looks as follows:
+          <para>An example query by "hw-address" for IPv4 lease looks
+          as follows:
 <screen>
 {
     "command": "lease4-get",
@@ -1485,6 +1522,20 @@ The commands can take a number of additional optional parameters:
 
           </para>
 
+          <para>An example query by "client-id" for IPv4 lease looks
+          as follows:
+<screen>
+{
+    "command": "lease4-get",
+    "arguments": {
+        "identifier-type": "client-id",
+        "identifier": "01:01:02:03:04:05:06",
+        "subnet-id": 44
+    }
+}</screen>
+
+          </para>
+
           <para>An example query by (subnet-id, identifier-type,
           identifier, iaid, type) for IPv6 lease looks as follows:
 <screen>
@@ -1546,8 +1597,9 @@ An example result returned when the host was found:
           used, no matter who may use it). The second query uses
           identifiers. For maximum flexibility, this interface uses identifiers
           as a pair of values: type and the actual identifier. Currently
-          supported identifiers are "hw-address" and "duid", but additional
-          types may be added in the future. </para>
+          supported identifiers are "hw-address" (IPv4 only), "client-id"
+          (IPv4 only) and "duid" (IPv6 only), but additional types may be added
+          in the future. </para>
 
           <para>
             An example command for deleting a host reservation by address looks
@@ -1560,8 +1612,7 @@ An example result returned when the host was found:
     }
 }</screen>
 
-An example IPv4 lease deletion by (subnet-id, identifier-type, identifier) looks
-as follows:
+An example IPv4 lease deletion by "hw-address" looks as follows:
 
 <screen>{
   "command": "lease4-del",
@@ -1573,9 +1624,9 @@ as follows:
 }</screen>
           </para>
 
-          <para><command>leaseX-get</command> returns a result that
+          <para><command>leaseX-del</command> returns a result that
           indicates a outcome of the operation. It has one of the
-          following values: 0 (success), 1 (error) or 2 (empty). The
+          following values: 0 (success), 1 (error) or 3 (empty). The
           empty result means that a query has been completed properly,
           but the object (a lease in this case) has not been found.
           </para>

+ 45 - 13
src/hooks/dhcp/lease_cmds/lease_cmds.cc

@@ -39,24 +39,17 @@ namespace lease_cmds {
 /// @brief Wrapper class around reservation command handlers.
 class LeaseCmdsImpl : private CmdsImpl {
 public:
-    /// @brief Parameters specified for reservation-get and reservation-del
-    ///
-    /// As both call types (get and delete) need specify which reservation to
-    /// act on, they have the same set of parameters. In particular, those
-    /// two call types support the following sets of parameters:
-    /// - address
-    /// - subnet-id, identifier-type, identifier-value (v4)
-    /// - subnet-id, lease-type, iaid, identifier-type, identifier-value (v6)
-    ///
-    /// This class stores those parameters and is used to pass them around.
+
+    /// @brief Parameters specified for lease commands.
     class Parameters {
     public:
 
         /// @brief specifies type of query (by IP addr, by hwaddr, by DUID)
         typedef enum {
-            TYPE_ADDR,    ///< query by IP address (either v4 or v6)
-            TYPE_HWADDR,  ///< query by hardware address (v4 only)
-            TYPE_DUID     ///< query by DUID (v6 only)
+            TYPE_ADDR,      ///< query by IP address (either v4 or v6)
+            TYPE_HWADDR,    ///< query by hardware address (v4 only)
+            TYPE_DUID,      ///< query by DUID (v6 only)
+            TYPE_CLIENT_ID  ///< query by client identifier (v4 only).
         } Type;
 
         /// @brief Specifies subnet-id (always used)
@@ -71,6 +64,9 @@ public:
         /// @brief Specifies identifier value (used when query_type is TYPE_DUID)
         isc::dhcp::DuidPtr duid;
 
+        /// @brief Specifies identifier value (used when query_type is TYPE_CLIENT_ID)
+        isc::dhcp::ClientIdPtr client_id;
+
         /// @brief Attempts to covert text to one of specified types
         ///
         /// Supported values are: "address", hw-address and duid.
@@ -85,6 +81,8 @@ public:
                 return (Parameters::TYPE_HWADDR);
             } else if (txt == "duid") {
                 return (Parameters::TYPE_DUID);
+            } else if (txt == "client-id") {
+                return (Parameters::TYPE_CLIENT_ID);
             } else {
                 isc_throw(BadValue, "Incorrect identifier type: "
                           << txt << ", the only supported values are: "
@@ -345,6 +343,10 @@ LeaseCmdsImpl::getParameters(bool v6, const ConstElementPtr& params) {
         x.hwaddr = HWAddrPtr(new HWAddr(hw));
         break;
     }
+    case Parameters::TYPE_CLIENT_ID: {
+        x.client_id = ClientId::fromText(ident->stringValue());
+        break;
+    }
     case Parameters::TYPE_DUID: {
         DUID duid = DUID::fromText(ident->stringValue());
         x.duid = DuidPtr(new DUID(duid));
@@ -411,6 +413,19 @@ LeaseCmdsImpl::leaseGetHandler(CalloutHandle& handle) {
             }
             break;
 
+        case Parameters::TYPE_CLIENT_ID:
+            if (v4) {
+                if (!p.client_id) {
+                    isc_throw(InvalidParameter, "Program error: Query by client-id "
+                                                "requires client-id to be specified");
+                }
+
+                lease4 = LeaseMgrFactory::instance().getLease4(*p.client_id, p.subnet_id);
+            } else {
+                isc_throw(isc::InvalidParameter, "Query by client-id is not allowed in v6.");
+            }
+            break;
+
         default: {
             isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
             break;
@@ -473,6 +488,23 @@ LeaseCmdsImpl::lease4DelHandler(CalloutHandle& handle) {
             addr = lease4->addr_;
             break;
 
+        case Parameters::TYPE_CLIENT_ID:
+            if (!p.client_id) {
+                isc_throw(InvalidParameter, "Program error: Query by client-id "
+                                            "requires client-id to be specified");
+            }
+
+            // Let's see if there's such a lease at all.
+            lease4 = LeaseMgrFactory::instance().getLease4(*p.client_id, p.subnet_id);
+            if (!lease4) {
+                setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
+                return (0);
+            }
+
+            // Found it, can use it as is.
+            addr = lease4->addr_;
+            break;
+
         case Parameters::TYPE_DUID:
             isc_throw(InvalidParameter, "Delete by duid is not allowed in v4.");
             break;

+ 114 - 1
src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc

@@ -1047,7 +1047,7 @@ TEST_F(LeaseCmdsTest, Lease4GetByAddr) {
     ASSERT_TRUE(lease);
 
     // Let's check if the response makes any sense.
-    checkLease4(lease, "192.0.2.1", 44, "08:08:08:08:08:08", false);
+    checkLease4(lease, "192.0.2.1", 44, "08:08:08:08:08:08", true);
 }
 
 // Checks that lease4-get can handle a situation when the query is
@@ -1122,6 +1122,73 @@ TEST_F(LeaseCmdsTest, Lease6GetByAddr6NotFound) {
     testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
 }
 
+// Checks that lease4-get can handle a situation when the query is
+// well formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease4GetByClientIdNotFound) {
+
+    // Initialize lease manager (false = v4, false = don't add a lease)
+    initLeaseMgr(false, false);
+
+    // No such lease.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-get\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"client-id\","
+        "        \"identifier\": \"01:02:03:04\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "Lease not found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
+}
+
+// Check that lease4-get can find a lease by client identifier.
+TEST_F(LeaseCmdsTest, Lease4GetByClientId) {
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-get\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"client-id\","
+        "        \"identifier\": \"42:42:42:42:42:42:42:42\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Now check that the lease parameters were indeed returned.
+    ASSERT_TRUE(rsp);
+    ConstElementPtr lease = rsp->get("arguments");
+    ASSERT_TRUE(lease);
+
+    // Let's check if the response makes any sense.
+    checkLease4(lease, "192.0.2.1", 44, "08:08:08:08:08:08", false);
+}
+
+// Checks that lease6-get rejects queries by client-id.
+TEST_F(LeaseCmdsTest, Lease6GetByClientIdInvalidType) {
+
+    // Initialize lease manager (true = v6, true = add a lease)
+    initLeaseMgr(true, true);
+
+    // client-id query is allowed in v4 only.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease6-get\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"client-id\","
+        "        \"identifier\": \"01:02:03:04\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "Query by client-id is not allowed in v6.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+}
+
 // Checks that lease6-get(subnet-id, addr) can handle a situation when
 // the query is correctly formed, but the lease is not there.
 TEST_F(LeaseCmdsTest, Lease6GetByDuidNotFound) {
@@ -1794,6 +1861,52 @@ TEST_F(LeaseCmdsTest, Lease4DelByHWAddr) {
     EXPECT_FALSE(lmptr_->getLease4(IOAddress("192.0.2.1")));
 }
 
+// Checks that lease4-del can handle a situation when the query is
+// well formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease4DelByClientIdNotFound) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // No such lease.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"client-id\","
+        "        \"identifier\": \"01:02:03:04\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease not found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
+
+    // Make sure the lease is still there.
+    EXPECT_TRUE(lmptr_->getLease4(IOAddress("192.0.2.1")));
+}
+
+// Checks that lease4-del can find and delete a lease by client identifier.
+TEST_F(LeaseCmdsTest, Lease4DelByClientId) {
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Invalid
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"client-id\","
+        "        \"identifier\": \"42:42:42:42:42:42:42:42\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease deleted.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Make sure the lease is really gone.
+    EXPECT_FALSE(lmptr_->getLease4(IOAddress("192.0.2.1")));
+}
+
 // Checks that lease6-del(addr) can handle a situation when
 // the query is correctly formed, but the lease is not there.
 TEST_F(LeaseCmdsTest, Lease6DelByAddr6NotFound) {