BIND 10 master, updated. fef265b2e3bfae238c91bfd820bed760efc748aa [master] Merge branch 'trac2984' (additional DHCPv6 hooks)

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Aug 9 15:10:20 UTC 2013


The branch, master has been updated
       via  fef265b2e3bfae238c91bfd820bed760efc748aa (commit)
       via  540dd0449121094a56f294c500c2ed811f6016b6 (commit)
       via  1b46569fab6d606359ada85f6736951c969e8eb0 (commit)
       via  2e4d7c7f734e5d10881698e05a26193199558fc5 (commit)
       via  ceb084b6e3c728d23154c5ea4ae8d10bb3b91477 (commit)
       via  d165e1c0d34e34a24b4519106af41af74d92b197 (commit)
       via  9643f2fc5610a68278c7a1ea7cc167991467122e (commit)
       via  bc799623e178c6d3e979df3630b8dc65c92fbb62 (commit)
       via  105e9affbca307c53328b34302020d27435153f8 (commit)
       via  c9874eac89f0e49c56c3911446e2e2d0f6d48657 (commit)
       via  fb7ab395e160cdaefa9ecffb4a70343d24cb80b6 (commit)
       via  7d4a5388296c225d11014d6e123cf0ee2cc8eb9f (commit)
       via  762f2fe1566c467eab8d48444f3d0c0c388d9e9b (commit)
       via  f8d312a623932ae279f24e6ec9587696ab2418a1 (commit)
       via  988bb28c2391905a35e6f0c9113f78feb8f8bc97 (commit)
       via  8525babb4efb54926675d2d1a1398638cbc6676d (commit)
       via  4b0906418973479e742cf831d5acdb291384014e (commit)
       via  6f304d9ee4e85db2e3aa708ee31135c4e42ef347 (commit)
       via  61363a11804b7838e848b8f07cba13dce80e078f (commit)
      from  10d9ff6b5b241f41939bee5bc5304d24b3147e15 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit fef265b2e3bfae238c91bfd820bed760efc748aa
Merge: 10d9ff6 540dd04
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Fri Aug 9 17:10:08 2013 +0200

    [master] Merge branch 'trac2984' (additional DHCPv6 hooks)
    
    Conflicts:
    	ChangeLog
    	src/bin/dhcp6/dhcp6_srv.cc

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                        |   13 +-
 src/bin/dhcp6/dhcp6_hooks.dox                    |  126 +-
 src/bin/dhcp6/dhcp6_messages.mes                 |   51 +-
 src/bin/dhcp6/dhcp6_srv.cc                       |  404 ++++--
 src/bin/dhcp6/dhcp6_srv.h                        |   13 +-
 src/bin/dhcp6/tests/Makefile.am                  |    2 +
 src/bin/dhcp6/tests/dhcp6_srv_unittest.cc        | 1038 +--------------
 src/bin/dhcp6/tests/dhcp6_test_utils.h           |  403 ++++++
 src/bin/dhcp6/tests/hooks_unittest.cc            | 1457 ++++++++++++++++++++++
 src/lib/dhcp/pkt6.h                              |   31 +-
 src/lib/dhcp/tests/iface_mgr_unittest.cc         |    6 +-
 src/lib/dhcp/tests/pkt6_unittest.cc              |    4 +-
 tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc |   10 +-
 13 files changed, 2343 insertions(+), 1215 deletions(-)
 create mode 100644 src/bin/dhcp6/tests/dhcp6_test_utils.h
 create mode 100644 src/bin/dhcp6/tests/hooks_unittest.cc

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 35ce150..53e650c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,14 @@
-655.	[func]	tmark
+656.	[func]		tomek
+	Additional hooks (buffer6_receive, lease6_renew,
+	lease6_release, buffer6_send) added to the DHCPv6 server.
+	(Trac #2984, git 540dd0449121094a56f294c500c2ed811f6016b6)
+
+655.	[func]		tmark
 	Added D2UpdateMgr class to b10-dhcp-ddns. This class is the b10-dhcp-ddns
 	task master, instantiating and supervising transactions that carry out the
 	DNS updates needed to fulfill the requests (NameChangeRequests) received
 	from b10-dhcp-ddns clients (e.g. DHCP servers).
-	(Trac #3059 git d72675617d6b60e3eb6160305738771f015849ba) 
+	(Trac #3059 git d72675617d6b60e3eb6160305738771f015849ba)
 
 654.	[bug]		stephen
 	Always clear "skip" flag before calling any callouts on a hook.
@@ -61,7 +66,7 @@
 	(Trac #3054, git 0f845ed94f462dee85b67f056656b2a197878b04)
 
 645.	[func]		tomek
-	Added initial set of hooks (pk4_receive, subnet4_select,
+	Added initial set of hooks (pkt4_receive, subnet4_select,
 	lease4_select, pkt4_send) to the DHCPv6 server.
 	(Trac #2994, git be65cfba939a6a7abd3c93931ce35c33d3e8247b)
 
@@ -82,7 +87,7 @@
 	(Trac #3056, git 92ebabdbcf6168666b03d7f7fbb31f899be39322)
 
 642.	[func]		tomek
-	Added initial set of hooks (pk6_receive, subnet6_select,
+	Added initial set of hooks (pkt6_receive, subnet6_select,
 	lease6_select, pkt6_send) to the DHCPv6 server.
 	(Trac #2995, git d6de376f97313ba40fef989e4a437d184fdf70cc)
 
diff --git a/src/bin/dhcp6/dhcp6_hooks.dox b/src/bin/dhcp6/dhcp6_hooks.dox
index dba086b..b21ad74 100644
--- a/src/bin/dhcp6/dhcp6_hooks.dox
+++ b/src/bin/dhcp6/dhcp6_hooks.dox
@@ -49,20 +49,46 @@ The following list is ordered by appearance of specific hook points during
 packet processing. Hook points that are not specific to packet processing
 (e.g. lease expiration) will be added to the end of this list.
 
+ @subsection dhcpv6HooksBuffer6Receive buffer6_receive
+
+ - @b Arguments:
+   - name: @b query6, type: isc::dhcp::Pkt6Ptr, direction: <b>in/out</b>
+
+ - @b Description: This callout is executed when an incoming DHCPv6
+   packet is received and the data stored in a buffer. The sole argument -
+   query6 - contains a pointer to an isc::dhcp::Pkt6 object that contains
+   the received information stored in the data_ field. Basic information
+   like protocol, source/destination addresses and ports are set, but
+   the contents of the buffer have not yet been parsed.  That means that
+   the options_ field (that will eventually contain a list of objects
+   representing the received options) is empty, so none of the methods
+   that operate on it (e.g., getOption()) will work. The primary purpose
+   of this early call is to offer the ability to modify incoming packets
+   in their raw form. Unless you need to access to the raw data, it is
+   usually better to install your callout on the pkt6_receive hook point.
+
+ - <b>Skip flag action</b>: If any callout sets the skip flag, the
+   server will assume that the callout parsed the buffer and added then
+   necessary option objects to the options_ field; the server will not
+   do any parsing. If the callout sets the skip flag but does not parse
+   the buffer, the server will most probably drop the packet due to
+   the absence of mandatory options. If you want to drop the packet,
+   see the description of the skip flag in the pkt6_receive hook point.
+
  @subsection dhcpv6HooksPkt6Receive pkt6_receive
 
  - @b Arguments:
    - name: @b query6, type: isc::dhcp::Pkt6Ptr, direction: <b>in/out</b>
 
- - @b Description: this callout is executed when an incoming DHCPv6
+ - @b Description: This callout is executed when an incoming DHCPv6
    packet is received and its content is parsed. The sole argument -
    query6 - contains a pointer to an isc::dhcp::Pkt6 object that contains
    all information regarding incoming packet, including its source and
-   destination addresses, interface over which it was received, a list
+   destination addresses, the interface over which it was received, a list
    of all options present within and relay information.  All fields of
    the Pkt6 object can be modified at this time, except data_. (data_
    contains the incoming packet as raw buffer. By the time this hook is
-   reached, that information has already parsed and is available though
+   reached, that information has already been parsed and is available though
    other fields in the Pkt6 object.  For this reason, it doesn't make
    sense to modify it.)
 
@@ -77,7 +103,7 @@ packet processing. Hook points that are not specific to packet processing
    - name: @b subnet6, type: isc::dhcp::Subnet6Ptr, direction: <b>in/out</b>
    - name: @b subnet6collection, type: const isc::dhcp::Subnet6Collection *, direction: <b>in</b>
 
- - @b Description: this callout is executed when a subnet is being
+ - @b Description: This callout is executed when a subnet is being
    selected for the incoming packet. All parameters, addresses and
    prefixes will be assigned from that subnet. A callout can select a
    different subnet if it wishes so, the list of all subnets currently
@@ -89,14 +115,14 @@ packet processing. Hook points that are not specific to packet processing
    will continue, but will be severely limited (i.e. only global options
    will be assigned).
 
- at subsection dhcpv6HooksLeaseSelect lease6_select
+ at subsection dhcpv6HooksLease6Select lease6_select
 
  - @b Arguments:
    - name: @b subnet6, type: isc::dhcp::Subnet6Ptr, direction: <b>in</b>
    - name: @b fake_allocation, type: bool, direction: <b>in</b>
    - name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out</b>
 
- - @b Description: this callout is executed after the server engine
+ - @b Description: This callout is executed after the server engine
    has selected a lease for client's request but before the lease
    has been inserted into the database. Any modifications made to the
    isc::dhcp::Lease6 object will be stored in the lease's record in the
@@ -115,24 +141,98 @@ packet processing. Hook points that are not specific to packet processing
    Packet processing will continue and the client may get other addresses
    or prefixes if it requested more than one address and/or prefix.
 
+ at subsection dhcpv6HooksLease6Renew lease6_renew
+
+ - @b Arguments:
+   - name: @b query6, type: isc::dhcp::PktPtr, direction: <b>in</b>
+   - name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out</b>
+   - name: @b ia_na, type: boost::shared_ptr<Option6IA>, direction: <b>in/out</b>
+
+ - @b Description: This callout is executed when the server engine is
+   about to renew an existing lease. The client's request is provided as
+   the query6 argument and the existing lease with the appropriate fields
+   already modified is given in the lease6 argument. The final argument,
+   ia_na, is the IA_NA option that will be sent back to the client.
+   Callouts installed on the lease6_renew may modify the content of
+   the lease6 object. Care should be taken however, as that modified
+   information will be written to the database without any further
+   checking. \n\n Although the envisaged usage assumes modification of T1,
+   T2, preferred and valid lifetimes only, other parameters associated
+   with the lease may be modified as well. The only exception is the addr_
+   field, which must not be modified as it is used by the database to
+   select the existing lease to be updated. Care should also be taken to
+   modify the ia_na argument to match any changes in the lease6 argument.
+   If a client sends more than one IA_NA option, callouts will be called
+   separately for each IA_NA instance. The callout will be called only
+   when the update is valid, i.e. conditions such as an invalid addresses
+   or invalid iaid renewal attempts will not trigger this hook point.
+
+ - <b>Skip flag action</b>: If any callout installed on 'lease6_renew'
+   sets the skip flag, the server will not renew the lease. Under these
+   circumstances, the callout should modify the ia_na argument to reflect
+   this fact; otherwise the client will think the lease was renewed and continue
+   to operate under this assumption.
+
+ at subsection dhcpv6HooksLease6Release lease6_release
+
+ - @b Arguments:
+   - name: @b query6, type: isc::dhcp::PktPtr, direction: <b>in</b>
+   - name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out</b>
+
+ - @b Description: This callout is executed when the server engine is
+   about to release an existing lease. The client's request is provided
+   as the query6 argument and the existing lease is given in the lease6
+   argument.  Although the lease6 structure may be modified, it doesn't
+   make sense to do so as it will be destroyed immediately the callouts
+   finish execution.
+
+ - <b>Skip flag action</b>: If any callout installed on 'lease6_release'
+   sets the skip flag, the server will not delete the lease, which will
+   remain in the database until it expires. However, the server will send out
+   the response back to the client as if it did.
+
 @subsection dhcpv6HooksPkt6Send pkt6_send
 
  - @b Arguments:
    - name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: <b>in/out</b>
 
- - @b Description: this callout is executed when server's response
+ - @b Description: This callout is executed when server's response
    is about to be send back to the client. The sole argument - response6 -
    contains a pointer to an isc::dhcp::Pkt6 object that contains the
    packet, with set source and destination addresses, interface over which
    it will be send, list of all options and relay information.  All fields
-   of the Pkt6 object can be modified at this time, except bufferOut_.
-   (This is scratch space used for constructing the packet after all
-   pkt6_send callouts are complete, so any changes to that field will
-   be overwritten.)
+   of the Pkt6 object can be modified at this time.  It should be noted that
+   unless the callout sets the skip flag (see below), anything placed in the
+   bufferOut_ field will be overwritten when the callout returns.
+   (bufferOut_ is scratch space used for constructing the packet.)
+
+ - <b>Skip flag action</b>: If any callout sets the skip flag, the server
+   will assume that the callout did pack the transaction-id, message type and
+   option objects into the bufferOut_ field and will skip packing part.
+   Note that if the callout sets skip flag, but did not prepare the
+   output buffer, the server will send a zero sized message that will be
+   ignored by the client. If you want to drop the packet, please see
+   skip flag in the buffer6_send hook point.
+
+ at subsection dhcpv6HooksBuffer6Send buffer6_send
+
+ - @b Arguments:
+   - name: @b response6, type: isc::dhcp::Pkt6Ptr, direction: <b>in/out</b>
 
- - <b>Skip flag action</b>: if any callout sets the skip flag, the server
+ - @b Description: This callout is executed when server's response is
+   assembled into binary form and is about to be send back to the
+   client. The sole argument - response6 - contains a pointer to an
+   isc::dhcp::Pkt6 object that contains the packet, with set source and
+   destination addresses, interface over which it will be sent, list of
+   all options and relay information. All options are already encoded
+   in bufferOut_ field. It doesn't make sense to modify anything but the
+   contents of bufferOut_ at this time (although if it is a requirement
+   to modify that data, it will probably be found easier to modify the
+   option objects in a callout attached to the pkt6_send hook).
+
+ - <b>Skip flag action</b>: If any callout sets the skip flag, the server
    will drop this response packet. However, the original request packet
-   from a client was processed, so server's state was most likely changed
+   from a client has been processed, so server's state has most likely changed
    (e.g. lease was allocated). Setting this flag merely stops the change
    being communicated to the client.
 
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index feb332e..f66fc54 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -75,22 +75,50 @@ This message is printed when DHCPv6 server disables an interface from being
 used to receive DHCPv6 traffic. Sockets on this interface will not be opened
 by the Interface Manager until interface is enabled.
 
-% DHCP6_HOOK_PACKET_RCVD_SKIP received DHCPv6 packet was dropped, because a callout set skip flag.
+% DHCP6_HOOK_BUFFER_RCVD_SKIP received DHCPv6 buffer was dropped because a callout set the skip flag.
+This debug message is printed when a callout installed on buffer6_receive
+hook point set the skip flag. For this particular hook point, the
+setting of the flag by a callout instructs the server to drop the packet.
+
+% DHCP6_HOOK_BUFFER_SEND_SKIP prepared DHCPv6 response was dropped because a callout set the skip flag.
+This debug message is printed when a callout installed on buffer6_receive
+hook point set the skip flag. For this particular hook point, the
+setting of the flag by a callout instructs the server to drop the packet.
+Server completed all the processing (e.g. may have assigned, updated
+or released leases), but the response will not be send to the client.
+
+% DHCP6_HOOK_LEASE6_RENEW_SKIP DHCPv6 lease was not renewed because a callout set the skip flag.
+This debug message is printed when a callout installed on lease6_renew
+hook point set the skip flag. For this particular hook point, the setting
+of the flag by a callout instructs the server to not renew a lease. If
+client requested renewal of multiples leases (by sending multiple IA
+options), the server will skip the renewal of the one in question and
+will proceed with other renewals as usual.
+
+% DHCP6_HOOK_LEASE6_RELEASE_SKIP DHCPv6 lease was not released because a callout set the skip flag.
+This debug message is printed when a callout installed on lease6_release
+hook point set the skip flag. For this particular hook point, the
+setting of the flag by a callout instructs the server to not release
+a lease. If client requested release of multiples leases (by sending
+multiple IA options), the server will retains this particular lease and
+will proceed with other renewals as usual.
+
+% DHCP6_HOOK_PACKET_RCVD_SKIP received DHCPv6 packet was dropped because a callout set the skip flag.
 This debug message is printed when a callout installed on the pkt6_receive
-hook point sets the skip flag. For this particular hook point, the
+hook point set the skip flag. For this particular hook point, the
 setting of the flag by a callout instructs the server to drop the packet.
 
-% DHCP6_HOOK_PACKET_SEND_SKIP prepared DHCPv6 response was not sent, because a callout set skip flag.
+% DHCP6_HOOK_PACKET_SEND_SKIP prepared DHCPv6 response was not sent because a callout set the skip flag.
 This debug message is printed when a callout installed on the pkt6_send
-hook point sets the skip flag. For this particular hook point, the setting
+hook point set the skip flag. For this particular hook point, the setting
 of the flag by a callout instructs the server to drop the packet. This
 effectively means that the client will not get any response, even though
 the server processed client's request and acted on it (e.g. possibly
 allocated a lease).
 
-% DHCP6_HOOK_SUBNET6_SELECT_SKIP no subnet was selected, because a callout set skip flag.
+% DHCP6_HOOK_SUBNET6_SELECT_SKIP no subnet was selected because a callout set the skip flag.
 This debug message is printed when a callout installed on the
-subnet6_select hook point sets the skip flag. For this particular hook
+subnet6_select hook point set the skip flag. For this particular hook
 point, the setting of the flag instructs the server not to choose a
 subnet, an action that severely limits further processing; the server
 will be only able to offer global options - no addresses or prefixes
@@ -165,6 +193,11 @@ This error is output if the IPv6 DHCP server fails to send an assembled
 DHCP message to a client. The reason for the error is included in the
 message.
 
+% DHCP6_PACK_FAIL failed to assemble response correctly
+This error is output if the server failed to assemble the data to be
+returned to the client into a valid packet.  The reason is most likely
+to be to a programming error: please raise a bug report.
+
 % DHCP6_PARSER_COMMIT_EXCEPTION parser failed to commit changes
 On receipt of message containing details to a change of the IPv6 DHCP
 server configuration, a set of parsers were successfully created, but one
@@ -339,6 +372,12 @@ to a misconfiguration of the server. The packet processing will continue, but
 the response will only contain generic configuration parameters and no
 addresses or prefixes.
 
+% DHCP6_UNKNOWN_MSG_RECEIVED received unknown message (type %d) on interface %2
+This debug message is printed when server receives a message of unknown type.
+That could either mean missing functionality or invalid or broken relay or client.
+The list of formally defined message types is available here:
+www.iana.org/assignments/dhcpv6-parameters.
+
 % DHCP6_UNKNOWN_RELEASE received RELEASE from unknown client (duid=%1, iaid=%2)
 This warning message is printed when client attempts to release a lease,
 but no such lease is known by the server. See DHCP6_UNKNOWN_RENEW for
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index b2ba67b..90c3716 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -60,15 +60,23 @@ namespace {
 
 /// Structure that holds registered hook indexes
 struct Dhcp6Hooks {
+    int hook_index_buffer6_receive_;///< index for "buffer6_receive" hook point
     int hook_index_pkt6_receive_;   ///< index for "pkt6_receive" hook point
     int hook_index_subnet6_select_; ///< index for "subnet6_select" hook point
+    int hook_index_lease6_renew_;   ///< index for "lease6_renew" hook point
+    int hook_index_lease6_release_; ///< index for "lease6_release" hook point
     int hook_index_pkt6_send_;      ///< index for "pkt6_send" hook point
+    int hook_index_buffer6_send_;   ///< index for "buffer6_send" hook point
 
     /// Constructor that registers hook points for DHCPv6 engine
     Dhcp6Hooks() {
+        hook_index_buffer6_receive_= HooksManager::registerHook("buffer6_receive");
         hook_index_pkt6_receive_   = HooksManager::registerHook("pkt6_receive");
         hook_index_subnet6_select_ = HooksManager::registerHook("subnet6_select");
+        hook_index_lease6_renew_   = HooksManager::registerHook("lease6_renew");
+        hook_index_lease6_release_ = HooksManager::registerHook("lease6_release");
         hook_index_pkt6_send_      = HooksManager::registerHook("pkt6_send");
+        hook_index_buffer6_send_   = HooksManager::registerHook("buffer6_send");
     }
 };
 
@@ -94,8 +102,7 @@ namespace dhcp {
 static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
 
 Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
-:alloc_engine_(), serverid_(), shutdown_(true), hook_index_pkt6_receive_(-1),
-    hook_index_subnet6_select_(-1), hook_index_pkt6_send_(-1), port_(port)
+:alloc_engine_(), serverid_(), shutdown_(true), port_(port)
 {
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
@@ -129,17 +136,11 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
                 LOG_WARN(dhcp6_logger, DHCP6_SERVERID_WRITE_FAIL)
                     .arg(duid_file);
             }
-
         }
 
         // Instantiate allocation engine
         alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 
-        // Register hook points
-        hook_index_pkt6_receive_   = Hooks.hook_index_pkt6_receive_;
-        hook_index_subnet6_select_ = Hooks.hook_index_subnet6_select_;
-        hook_index_pkt6_send_      = Hooks.hook_index_pkt6_send_;
-
         /// @todo call loadLibraries() when handling configuration changes
 
     } catch (const std::exception &e) {
@@ -191,146 +192,236 @@ bool Dhcpv6Srv::run() {
             LOG_ERROR(dhcp6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
         }
 
-        if (query) {
-            if (!query->unpack()) {
-                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
-                          DHCP6_PACKET_PARSE_FAIL);
-                continue;
-            }
-            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
-                      .arg(query->getName());
-            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
-                      .arg(static_cast<int>(query->getType()))
-                      .arg(query->getBuffer().getLength())
-                      .arg(query->toText());
-
-            // Let's execute all callouts registered for packet_received
-            if (HooksManager::getHooksManager().calloutsPresent(hook_index_pkt6_receive_)) {
-                CalloutHandlePtr callout_handle = getCalloutHandle(query);
+        // Timeout may be reached or signal received, which breaks select() with no packet received
+        if (!query) {
+            continue;
+        }
 
-                // Delete previously set arguments
-                callout_handle->deleteAllArguments();
+        bool skip_unpack = false;
 
-                // Pass incoming packet as argument
-                callout_handle->setArgument("query6", query);
+        // The packet has just been received so contains the uninterpreted wire
+        // data; execute callouts registered for buffer6_receive.
+        if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
+            CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-                // Call callouts
-                HooksManager::callCallouts(hook_index_pkt6_receive_, *callout_handle);
+            // Delete previously set arguments
+            callout_handle->deleteAllArguments();
 
-                // Callouts decided to skip the next processing step. The next
-                // processing step would to process the packet, so skip at this
-                // stage means drop.
-                if (callout_handle->getSkip()) {
-                    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP);
-                    continue;
-                }
+            // Pass incoming packet as argument
+            callout_handle->setArgument("query6", query);
 
-                callout_handle->getArgument("query6", query);
+            // Call callouts
+            HooksManager::callCallouts(Hooks.hook_index_buffer6_receive_, *callout_handle);
+
+            // Callouts decided to skip the next processing step. The next
+            // processing step would to parse the packet, so skip at this
+            // stage means that callouts did the parsing already, so server
+            // should skip parsing.
+            if (callout_handle->getSkip()) {
+                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_RCVD_SKIP);
+                skip_unpack = true;
             }
 
-            try {
-                switch (query->getType()) {
-                case DHCPV6_SOLICIT:
-                    rsp = processSolicit(query);
-                    break;
+            callout_handle->getArgument("query6", query);
+        }
 
-                case DHCPV6_REQUEST:
-                    rsp = processRequest(query);
-                    break;
+        // Unpack the packet information unless the buffer6_receive callouts
+        // indicated they did it
+        if (!skip_unpack) {
+            if (!query->unpack()) {
+                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
+                          DHCP6_PACKET_PARSE_FAIL);
+                continue;
+            }
+        }
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
+            .arg(query->getName());
+        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
+            .arg(static_cast<int>(query->getType()))
+            .arg(query->getBuffer().getLength())
+            .arg(query->toText());
+
+        // At this point the information in the packet has been unpacked into
+        // the various packet fields and option objects has been cretated.
+        // Execute callouts registered for packet6_receive.
+        if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_pkt6_receive_)) {
+            CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+            // Delete previously set arguments
+            callout_handle->deleteAllArguments();
+
+            // Pass incoming packet as argument
+            callout_handle->setArgument("query6", query);
+
+            // Call callouts
+            HooksManager::callCallouts(Hooks.hook_index_pkt6_receive_, *callout_handle);
+
+            // Callouts decided to skip the next processing step. The next
+            // processing step would to process the packet, so skip at this
+            // stage means drop.
+            if (callout_handle->getSkip()) {
+                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP);
+                continue;
+            }
 
-                case DHCPV6_RENEW:
-                    rsp = processRenew(query);
-                    break;
+            callout_handle->getArgument("query6", query);
+        }
 
-                case DHCPV6_REBIND:
-                    rsp = processRebind(query);
+        try {
+            switch (query->getType()) {
+            case DHCPV6_SOLICIT:
+                rsp = processSolicit(query);
                     break;
 
-                case DHCPV6_CONFIRM:
-                    rsp = processConfirm(query);
-                    break;
+            case DHCPV6_REQUEST:
+                rsp = processRequest(query);
+                break;
+
+            case DHCPV6_RENEW:
+                rsp = processRenew(query);
+                break;
+
+            case DHCPV6_REBIND:
+                rsp = processRebind(query);
+                break;
+
+            case DHCPV6_CONFIRM:
+                rsp = processConfirm(query);
+                break;
+
+            case DHCPV6_RELEASE:
+                rsp = processRelease(query);
+                break;
+
+            case DHCPV6_DECLINE:
+                rsp = processDecline(query);
+                break;
+
+            case DHCPV6_INFORMATION_REQUEST:
+                rsp = processInfRequest(query);
+                break;
+
+            default:
+                // We received a packet type that we do not recognize.
+                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_UNKNOWN_MSG_RECEIVED)
+                    .arg(static_cast<int>(query->getType()))
+                    .arg(query->getIface());
+                // Only action is to output a message if debug is enabled,
+                // and that will be covered by the debug statement before
+                // the "switch" statement.
+                ;
+            }
 
-                case DHCPV6_RELEASE:
-                    rsp = processRelease(query);
-                    break;
+        } catch (const RFCViolation& e) {
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
+                .arg(query->getName())
+                .arg(query->getRemoteAddr().toText())
+                .arg(e.what());
+
+        } catch (const isc::Exception& e) {
+
+            // Catch-all exception (at least for ones based on the isc
+            // Exception class, which covers more or less all that
+            // are explicitly raised in the BIND 10 code).  Just log
+            // the problem and ignore the packet. (The problem is logged
+            // as a debug message because debug is disabled by default -
+            // it prevents a DDOS attack based on the sending of problem
+            // packets.)
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
+                .arg(query->getName())
+                .arg(query->getRemoteAddr().toText())
+                .arg(e.what());
+        }
 
-                case DHCPV6_DECLINE:
-                    rsp = processDecline(query);
-                    break;
+        if (rsp) {
+            rsp->setRemoteAddr(query->getRemoteAddr());
+            rsp->setLocalAddr(query->getLocalAddr());
+            rsp->setRemotePort(DHCP6_CLIENT_PORT);
+            rsp->setLocalPort(DHCP6_SERVER_PORT);
+            rsp->setIndex(query->getIndex());
+            rsp->setIface(query->getIface());
+
+            // Specifies if server should do the packing
+            bool skip_pack = false;
+
+            // Server's reply packet now has all options and fields set.
+            // Options are represented by individual objects, but the
+            // output wire data has not been prepared yet.
+            // Execute all callouts registered for packet6_send
+            if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_pkt6_send_)) {
+                CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-                case DHCPV6_INFORMATION_REQUEST:
-                    rsp = processInfRequest(query);
-                    break;
+                // Delete all previous arguments
+                callout_handle->deleteAllArguments();
+
+                // Set our response
+                callout_handle->setArgument("response6", rsp);
 
-                default:
-                    // Only action is to output a message if debug is enabled,
-                    // and that will be covered by the debug statement before
-                    // the "switch" statement.
-                    ;
+                // Call all installed callouts
+                HooksManager::callCallouts(Hooks.hook_index_pkt6_send_, *callout_handle);
+
+                // Callouts decided to skip the next processing step. The next
+                // processing step would to pack the packet (create wire data).
+                // That step will be skipped if any callout sets skip flag.
+                // It essentially means that the callout already did packing,
+                // so the server does not have to do it again.
+                if (callout_handle->getSkip()) {
+                    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP);
+                    skip_pack = true;
                 }
+            }
 
-            } catch (const RFCViolation& e) {
-                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
-                    .arg(query->getName())
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(e.what());
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
+                      DHCP6_RESPONSE_DATA)
+                .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
 
-            } catch (const isc::Exception& e) {
-
-                // Catch-all exception (at least for ones based on the isc
-                // Exception class, which covers more or less all that
-                // are explicitly raised in the BIND 10 code).  Just log
-                // the problem and ignore the packet. (The problem is logged
-                // as a debug message because debug is disabled by default -
-                // it prevents a DDOS attack based on the sending of problem
-                // packets.)
-                LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
-                    .arg(query->getName())
-                    .arg(query->getRemoteAddr().toText())
-                    .arg(e.what());
+            if (!skip_pack) {
+                try {
+                    rsp->pack();
+                } catch (const std::exception& e) {
+                    LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL)
+                        .arg(e.what());
+                    continue;
+                }
             }
 
-            if (rsp) {
-                rsp->setRemoteAddr(query->getRemoteAddr());
-                rsp->setLocalAddr(query->getLocalAddr());
-                rsp->setRemotePort(DHCP6_CLIENT_PORT);
-                rsp->setLocalPort(DHCP6_SERVER_PORT);
-                rsp->setIndex(query->getIndex());
-                rsp->setIface(query->getIface());
+            try {
 
-                // Execute all callouts registered for packet6_send
-                if (HooksManager::getHooksManager().calloutsPresent(hook_index_pkt6_send_)) {
+                // Now all fields and options are constructed into output wire buffer.
+                // Option objects modification does not make sense anymore. Hooks
+                // can only manipulate wire buffer at this stage.
+                // Let's execute all callouts registered for buffer6_send
+                if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_buffer6_send_)) {
                     CalloutHandlePtr callout_handle = getCalloutHandle(query);
 
-                    // Delete all previous arguments
+                    // Delete previously set arguments
                     callout_handle->deleteAllArguments();
 
-                    // Set our response
+                    // Pass incoming packet as argument
                     callout_handle->setArgument("response6", rsp);
-
-                    // Call all installed callouts
-                    HooksManager::callCallouts(hook_index_pkt6_send_, *callout_handle);
-
+                    
+                    // Call callouts
+                    HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle);
+                    
                     // Callouts decided to skip the next processing step. The next
-                    // processing step would to send the packet, so skip at this
-                    // stage means "drop response".
+                    // processing step would to parse the packet, so skip at this
+                    // stage means drop.
                     if (callout_handle->getSkip()) {
-                        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP);
+                        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP);
                         continue;
                     }
+                    
+                    callout_handle->getArgument("response6", rsp);
                 }
 
                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
                           DHCP6_RESPONSE_DATA)
                     .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
 
-                try {
-                    rsp->pack();
-                    sendPacket(rsp);
-                } catch (const std::exception& e) {
-                    LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL)
-                              .arg(e.what());
-                }
+                sendPacket(rsp);
+            } catch (const std::exception& e) {
+                LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL)
+                    .arg(e.what());
             }
         }
     }
@@ -648,8 +739,8 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
         }
     }
 
-    // Let's execute all callouts registered for packet_received
-    if (HooksManager::getHooksManager().calloutsPresent(hook_index_subnet6_select_)) {
+    // Let's execute all callouts registered for subnet6_receive
+    if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_subnet6_select_)) {
         CalloutHandlePtr callout_handle = getCalloutHandle(question);
 
         // We're reusing callout_handle from previous calls
@@ -665,7 +756,7 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
         callout_handle->setArgument("subnet6collection", CfgMgr::instance().getSubnets6());
 
         // Call user (and server-side) callouts
-        HooksManager::callCallouts(hook_index_subnet6_select_, *callout_handle);
+        HooksManager::callCallouts(Hooks.hook_index_subnet6_select_, *callout_handle);
 
         // Callouts decided to skip this step. This means that no subnet will be
         // selected. Packet processing will continue, but it will be severly limited
@@ -852,7 +943,7 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
 
 OptionPtr
 Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
-                      Pkt6Ptr /* question */, boost::shared_ptr<Option6IA> ia) {
+                      const Pkt6Ptr& query, boost::shared_ptr<Option6IA> ia) {
     if (!subnet) {
         // There's no subnet select for this client. There's nothing to renew.
         boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
@@ -889,14 +980,15 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
         return (ia_rsp);
     }
 
+    // Keep the old data in case the callout tells us to skip update
+    Lease6 old_data = *lease;
+
     lease->preferred_lft_ = subnet->getPreferred();
     lease->valid_lft_ = subnet->getValid();
     lease->t1_ = subnet->getT1();
     lease->t2_ = subnet->getT2();
     lease->cltt_ = time(NULL);
 
-    LeaseMgrFactory::instance().updateLease6(lease);
-
     // Create empty IA_NA option with IAID matching the request.
     boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
 
@@ -907,6 +999,46 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
                                           lease->addr_, lease->preferred_lft_,
                                           lease->valid_lft_));
     ia_rsp->addOption(addr);
+
+    bool skip = false;
+    // Execute all callouts registered for packet6_send
+    if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease6_renew_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+        // Delete all previous arguments
+        callout_handle->deleteAllArguments();
+
+        // Pass the original packet
+        callout_handle->setArgument("query6", query);
+
+        // Pass the lease to be updated
+        callout_handle->setArgument("lease6", lease);
+
+        // Pass the IA option to be sent in response
+        callout_handle->setArgument("ia_na", ia_rsp);
+
+        // Call all installed callouts
+        HooksManager::callCallouts(Hooks.hook_index_lease6_renew_, *callout_handle);
+
+        // Callouts decided to skip the next processing step. The next
+        // processing step would to actually renew the lease, so skip at this
+        // stage means "keep the old lease as it is".
+        if (callout_handle->getSkip()) {
+            skip = true;
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RENEW_SKIP);
+        }
+    }
+
+    if (!skip) {
+        LeaseMgrFactory::instance().updateLease6(lease);
+    } else {
+        // Copy back the original date to the lease. For MySQL it doesn't make
+        // much sense, but for memfile, the Lease6Ptr points to the actual lease
+        // in memfile, so the actual update is performed when we manipulate fields
+        // of returned Lease6Ptr, the actual updateLease6() is no-op.
+        *lease = old_data;
+    }
+
     return (ia_rsp);
 }
 
@@ -1025,7 +1157,7 @@ Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
 }
 
 OptionPtr
-Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
+Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
                         int& general_status, boost::shared_ptr<Option6IA> ia) {
     // Release can be done in one of two ways:
     // Approach 1: extract address from client's IA_NA and see if it belongs
@@ -1109,9 +1241,43 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
     // It is not necessary to check if the address matches as we used
     // getLease6(addr) method that is supposed to return a proper lease.
 
+    bool skip = false;
+    // Execute all callouts registered for packet6_send
+    if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease6_release_)) {
+        CalloutHandlePtr callout_handle = getCalloutHandle(query);
+
+        // Delete all previous arguments
+        callout_handle->deleteAllArguments();
+
+        // Pass the original packet
+        callout_handle->setArgument("query6", query);
+
+        // Pass the lease to be updated
+        callout_handle->setArgument("lease6", lease);
+
+        // Call all installed callouts
+        HooksManager::callCallouts(Hooks.hook_index_lease6_release_, *callout_handle);
+
+        // Callouts decided to skip the next processing step. The next
+        // processing step would to send the packet, so skip at this
+        // stage means "drop response".
+        if (callout_handle->getSkip()) {
+            skip = true;
+            LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_SKIP);
+        }
+    }
+
     // Ok, we've passed all checks. Let's release this address.
+    bool success = false; // was the removal operation succeessful?
+
+    if (!skip) {
+        success = LeaseMgrFactory::instance().deleteLease(lease->addr_);
+    }
+
+    // Here the success should be true if we removed lease successfully
+    // and false if skip flag was set or the removal failed for whatever reason
 
-    if (!LeaseMgrFactory::instance().deleteLease(lease->addr_)) {
+    if (!success) {
         ia_rsp->addOption(createStatusCode(STATUS_UnspecFail,
                           "Server failed to release a lease"));
 
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 0a4fafd..c5c67e8 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -227,11 +227,11 @@ protected:
     ///
     /// @param subnet subnet the sender belongs to
     /// @param duid client's duid
-    /// @param question client's message
+    /// @param query client's message
     /// @param ia IA_NA option that is being renewed
     /// @return IA_NA option (server's response)
     OptionPtr renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
-                         Pkt6Ptr question, boost::shared_ptr<Option6IA> ia);
+                         const Pkt6Ptr& query, boost::shared_ptr<Option6IA> ia);
 
     /// @brief Releases specific IA_NA option
     ///
@@ -246,11 +246,11 @@ protected:
     /// release process fails.
     ///
     /// @param duid client's duid
-    /// @param question client's message
+    /// @param query client's message
     /// @param general_status a global status (it may be updated in case of errors)
     /// @param ia IA_NA option that is being renewed
     /// @return IA_NA option (server's response)
-    OptionPtr releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
+    OptionPtr releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
                            int& general_status,
                            boost::shared_ptr<Option6IA> ia);
 
@@ -383,11 +383,6 @@ private:
     /// @return a callout handle to be used in hooks related to said packet
     isc::hooks::CalloutHandlePtr getCalloutHandle(const Pkt6Ptr& pkt);
 
-    /// Indexes for registered hook points
-    int hook_index_pkt6_receive_;
-    int hook_index_subnet6_select_;
-    int hook_index_pkt6_send_;
-
     /// UDP port number on which server listens.
     uint16_t port_;
 };
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index e8f0fca..293173c 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -49,6 +49,8 @@ TESTS += dhcp6_unittests
 
 dhcp6_unittests_SOURCES  = dhcp6_unittests.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
+dhcp6_unittests_SOURCES += hooks_unittest.cc
+dhcp6_unittests_SOURCES += dhcp6_test_utils.h
 dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc
 dhcp6_unittests_SOURCES += config_parser_unittest.cc
 dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index c5ced8d..6b8d122 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -15,7 +15,6 @@
 #include <config.h>
 
 #include <asiolink/io_address.h>
-#include <config/ccsession.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/duid.h>
 #include <dhcp/option.h>
@@ -26,7 +25,6 @@
 #include <dhcp/option_int_array.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp6/config_parser.h>
-#include <dhcp6/dhcp6_srv.h>
 #include <dhcp/dhcp6.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/lease_mgr.h>
@@ -35,20 +33,18 @@
 #include <util/buffer.h>
 #include <util/range_utilities.h>
 #include <hooks/server_hooks.h>
-#include <hooks/hooks_manager.h>
 
+#include <dhcp6/tests/dhcp6_test_utils.h>
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
 #include <unistd.h>
 #include <fstream>
 #include <iostream>
 #include <sstream>
-#include <list>
 
 using namespace isc;
+using namespace isc::test;
 using namespace isc::asiolink;
-using namespace isc::config;
-using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::util;
 using namespace isc::hooks;
@@ -58,353 +54,6 @@ using namespace std;
 // Maybe it should be isc::test?
 namespace {
 
-class NakedDhcpv6Srv: public Dhcpv6Srv {
-    // "naked" Interface Manager, exposes internal members
-public:
-    NakedDhcpv6Srv(uint16_t port) : Dhcpv6Srv(port) {
-        // Open the "memfile" database for leases
-        std::string memfile = "type=memfile";
-        LeaseMgrFactory::create(memfile);
-    }
-
-    /// @brief fakes packet reception
-    /// @param timeout ignored
-    ///
-    /// The method receives all packets queued in receive
-    /// queue, one after another. Once the queue is empty,
-    /// it initiates the shutdown procedure.
-    ///
-    /// See fake_received_ field for description
-    virtual Pkt6Ptr receivePacket(int /*timeout*/) {
-
-        // If there is anything prepared as fake incoming
-        // traffic, use it
-        if (!fake_received_.empty()) {
-            Pkt6Ptr pkt = fake_received_.front();
-            fake_received_.pop_front();
-            return (pkt);
-        }
-
-        // If not, just trigger shutdown and
-        // return immediately
-        shutdown();
-        return (Pkt6Ptr());
-    }
-
-    /// @brief fake packet sending
-    ///
-    /// Pretend to send a packet, but instead just store
-    /// it in fake_send_ list where test can later inspect
-    /// server's response.
-    virtual void sendPacket(const Pkt6Ptr& pkt) {
-        fake_sent_.push_back(pkt);
-    }
-
-    /// @brief adds a packet to fake receive queue
-    ///
-    /// See fake_received_ field for description
-    void fakeReceive(const Pkt6Ptr& pkt) {
-        fake_received_.push_back(pkt);
-    }
-
-    virtual ~NakedDhcpv6Srv() {
-        // Close the lease database
-        LeaseMgrFactory::destroy();
-    }
-
-    using Dhcpv6Srv::processSolicit;
-    using Dhcpv6Srv::processRequest;
-    using Dhcpv6Srv::processRenew;
-    using Dhcpv6Srv::processRelease;
-    using Dhcpv6Srv::createStatusCode;
-    using Dhcpv6Srv::selectSubnet;
-    using Dhcpv6Srv::sanityCheck;
-    using Dhcpv6Srv::loadServerID;
-    using Dhcpv6Srv::writeServerID;
-
-    /// @brief packets we pretend to receive
-    ///
-    /// Instead of setting up sockets on interfaces that change between OSes, it
-    /// is much easier to fake packet reception. This is a list of packets that
-    /// we pretend to have received. You can schedule new packets to be received
-    /// using fakeReceive() and NakedDhcpv6Srv::receivePacket() methods.
-    list<Pkt6Ptr> fake_received_;
-
-    list<Pkt6Ptr> fake_sent_;
-};
-
-static const char* DUID_FILE = "server-id-test.txt";
-
-// test fixture for any tests requiring blank/empty configuration
-// serves as base class for additional tests
-class NakedDhcpv6SrvTest : public ::testing::Test {
-public:
-
-    NakedDhcpv6SrvTest() : rcode_(-1) {
-        // it's ok if that fails. There should not be such a file anyway
-        unlink(DUID_FILE);
-
-        const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
-
-        // There must be some interface detected
-        if (ifaces.empty()) {
-            // We can't use ASSERT in constructor
-            ADD_FAILURE() << "No interfaces detected.";
-        }
-
-        valid_iface_ = ifaces.begin()->getName();
-    }
-
-    // Generate IA_NA option with specified parameters
-    boost::shared_ptr<Option6IA> generateIA(uint32_t iaid, uint32_t t1, uint32_t t2) {
-        boost::shared_ptr<Option6IA> ia =
-            boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, iaid));
-        ia->setT1(t1);
-        ia->setT2(t2);
-        return (ia);
-    }
-
-    /// @brief generates interface-id option, based on text
-    ///
-    /// @param iface_id textual representation of the interface-id content
-    ///
-    /// @return pointer to the option object
-    OptionPtr generateInterfaceId(const string& iface_id) {
-        OptionBuffer tmp(iface_id.begin(), iface_id.end());
-        return OptionPtr(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
-    }
-
-    // Generate client-id option
-    OptionPtr generateClientId(size_t duid_size = 32) {
-
-        OptionBuffer clnt_duid(duid_size);
-        for (int i = 0; i < duid_size; i++) {
-            clnt_duid[i] = 100 + i;
-        }
-
-        duid_ = DuidPtr(new DUID(clnt_duid));
-
-        return (OptionPtr(new Option(Option::V6, D6O_CLIENTID,
-                                     clnt_duid.begin(),
-                                     clnt_duid.begin() + duid_size)));
-    }
-
-    // Checks if server response (ADVERTISE or REPLY) includes proper server-id.
-    void checkServerId(const Pkt6Ptr& rsp, const OptionPtr& expected_srvid) {
-        // check that server included its server-id
-        OptionPtr tmp = rsp->getOption(D6O_SERVERID);
-        EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
-        ASSERT_EQ(tmp->len(), expected_srvid->len() );
-        EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
-    }
-
-    // Checks if server response (ADVERTISE or REPLY) includes proper client-id.
-    void checkClientId(const Pkt6Ptr& rsp, const OptionPtr& expected_clientid) {
-        // check that server included our own client-id
-        OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
-        ASSERT_TRUE(tmp);
-        EXPECT_EQ(expected_clientid->getType(), tmp->getType());
-        ASSERT_EQ(expected_clientid->len(), tmp->len());
-
-        // check that returned client-id is valid
-        EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
-    }
-
-    // Checks if server response is a NAK
-    void checkNakResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
-                          uint32_t expected_transid,
-                          uint16_t expected_status_code) {
-        // Check if we get response at all
-        checkResponse(rsp, expected_message_type, expected_transid);
-
-        // Check that IA_NA was returned
-        OptionPtr option_ia_na = rsp->getOption(D6O_IA_NA);
-        ASSERT_TRUE(option_ia_na);
-
-        // check that the status is no address available
-        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(option_ia_na);
-        ASSERT_TRUE(ia);
-
-        checkIA_NAStatusCode(ia, expected_status_code);
-    }
-
-    // Checks that server rejected IA_NA, i.e. that it has no addresses and
-    // that expected status code really appears there. In some limited cases
-    // (reply to RELEASE) it may be used to verify positive case, where
-    // IA_NA response is expected to not include address.
-    //
-    // Status code indicates type of error encountered (in theory it can also
-    // indicate success, but servers typically don't send success status
-    // as this is the default result and it saves bandwidth)
-    void checkIA_NAStatusCode(const boost::shared_ptr<Option6IA>& ia,
-                            uint16_t expected_status_code) {
-        // Make sure there is no address assigned.
-        EXPECT_FALSE(ia->getOption(D6O_IAADDR));
-
-        // T1, T2 should be zeroed
-        EXPECT_EQ(0, ia->getT1());
-        EXPECT_EQ(0, ia->getT2());
-
-        OptionCustomPtr status =
-            boost::dynamic_pointer_cast<OptionCustom>(ia->getOption(D6O_STATUS_CODE));
-
-        // It is ok to not include status success as this is the default behavior
-        if (expected_status_code == STATUS_Success && !status) {
-            return;
-        }
-
-        EXPECT_TRUE(status);
-
-        if (status) {
-            // We don't have dedicated class for status code, so let's just interpret
-            // first 2 bytes as status. Remainder of the status code option content is
-            // just a text explanation what went wrong.
-            EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
-                      status->readInteger<uint16_t>(0));
-        }
-    }
-
-    void checkMsgStatusCode(const Pkt6Ptr& msg, uint16_t expected_status) {
-        OptionCustomPtr status =
-            boost::dynamic_pointer_cast<OptionCustom>(msg->getOption(D6O_STATUS_CODE));
-
-        // It is ok to not include status success as this is the default behavior
-        if (expected_status == STATUS_Success && !status) {
-            return;
-        }
-
-        EXPECT_TRUE(status);
-        if (status) {
-            // We don't have dedicated class for status code, so let's just interpret
-            // first 2 bytes as status. Remainder of the status code option content is
-            // just a text explanation what went wrong.
-            EXPECT_EQ(static_cast<uint16_t>(expected_status),
-                      status->readInteger<uint16_t>(0));
-        }
-    }
-
-    // Basic checks for generated response (message type and transaction-id).
-    void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
-                       uint32_t expected_transid) {
-        ASSERT_TRUE(rsp);
-        EXPECT_EQ(expected_message_type, rsp->getType());
-        EXPECT_EQ(expected_transid, rsp->getTransid());
-    }
-
-    virtual ~NakedDhcpv6SrvTest() {
-        // Let's clean up if there is such a file.
-        unlink(DUID_FILE);
-        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
-                                                 "pkt6_receive");
-        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
-                                                 "pkt6_send");
-        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
-                                                 "subnet6_select");
-
-    };
-
-    // A DUID used in most tests (typically as client-id)
-    DuidPtr duid_;
-
-    int rcode_;
-    ConstElementPtr comment_;
-
-    // Name of a valid network interface
-    string valid_iface_;
-};
-
-// Provides suport for tests against a preconfigured subnet6
-// extends upon NakedDhcp6SrvTest
-class Dhcpv6SrvTest : public NakedDhcpv6SrvTest {
-public:
-    /// Name of the server-id file (used in server-id tests)
-
-    // these are empty for now, but let's keep them around
-    Dhcpv6SrvTest() {
-        subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
-                                         2000, 3000, 4000));
-        pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
-        subnet_->addPool(pool_);
-
-        CfgMgr::instance().deleteSubnets6();
-        CfgMgr::instance().addSubnet6(subnet_);
-    }
-
-    // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
-    // It returns IAADDR option for each chaining with checkIAAddr method.
-    boost::shared_ptr<Option6IAAddr> checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
-                                            uint32_t expected_t1, uint32_t expected_t2) {
-        OptionPtr tmp = rsp->getOption(D6O_IA_NA);
-        // Can't use ASSERT_TRUE() in method that returns something
-        if (!tmp) {
-            ADD_FAILURE() << "IA_NA option not present in response";
-            return (boost::shared_ptr<Option6IAAddr>());
-        }
-
-        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
-        if (!ia) {
-            ADD_FAILURE() << "IA_NA cannot convert option ptr to Option6";
-            return (boost::shared_ptr<Option6IAAddr>());
-        }
-
-        EXPECT_EQ(expected_iaid, ia->getIAID());
-        EXPECT_EQ(expected_t1, ia->getT1());
-        EXPECT_EQ(expected_t2, ia->getT2());
-
-        tmp = ia->getOption(D6O_IAADDR);
-        boost::shared_ptr<Option6IAAddr> addr = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
-        return (addr);
-    }
-
-    // Check that generated IAADDR option contains expected address
-    // and lifetime values match the configured subnet
-    void checkIAAddr(const boost::shared_ptr<Option6IAAddr>& addr,
-                     const IOAddress& expected_addr,
-                     uint32_t /* expected_preferred */,
-                     uint32_t /* expected_valid */) {
-
-        // Check that the assigned address is indeed from the configured pool.
-        // Note that when comparing addresses, we compare the textual
-        // representation. IOAddress does not support being streamed to
-        // an ostream, which means it can't be used in EXPECT_EQ.
-        EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
-        EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
-        EXPECT_EQ(addr->getPreferred(), subnet_->getPreferred());
-        EXPECT_EQ(addr->getValid(), subnet_->getValid());
-    }
-
-    // Checks if the lease sent to client is present in the database
-    // and is valid when checked agasint the configured subnet
-    Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
-                         boost::shared_ptr<Option6IAAddr> addr) {
-        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(ia_na);
-
-        Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(addr->getAddress());
-        if (!lease) {
-            cout << "Lease for " << addr->getAddress().toText()
-                 << " not found in the database backend.";
-            return (Lease6Ptr());
-        }
-
-        EXPECT_EQ(addr->getAddress().toText(), lease->addr_.toText());
-        EXPECT_TRUE(*lease->duid_ == *duid);
-        EXPECT_EQ(ia->getIAID(), lease->iaid_);
-        EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
-
-        return (lease);
-    }
-
-    ~Dhcpv6SrvTest() {
-        CfgMgr::instance().deleteSubnets6();
-    };
-
-    // A subnet used in most tests
-    Subnet6Ptr subnet_;
-
-    // A pool used in most tests
-    Pool6Ptr pool_;
-};
-
 // This test verifies that incoming SOLICIT can be handled properly when
 // there are no subnets configured.
 //
@@ -1832,689 +1481,6 @@ TEST_F(Dhcpv6SrvTest, ServerID) {
     EXPECT_EQ(duid1_text, text);
 }
 
-// Checks if hooks are implemented properly.
-TEST_F(Dhcpv6SrvTest, Hooks) {
-    NakedDhcpv6Srv srv(0);
-
-    // check if appropriate hooks are registered
-    int hook_index_pkt6_received = -1;
-    int hook_index_select_subnet = -1;
-    int hook_index_pkt6_send     = -1;
-
-    // check if appropriate indexes are set
-    EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
-                    .getIndex("pkt6_receive"));
-    EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
-                    .getIndex("subnet6_select"));
-    EXPECT_NO_THROW(hook_index_pkt6_send     = ServerHooks::getServerHooks()
-                    .getIndex("pkt6_send"));
-
-    EXPECT_TRUE(hook_index_pkt6_received > 0);
-    EXPECT_TRUE(hook_index_select_subnet > 0);
-    EXPECT_TRUE(hook_index_pkt6_send > 0);
-}
-
-// This function returns buffer for very simple Solicit
-Pkt6* captureSimpleSolicit() {
-    Pkt6* pkt;
-    uint8_t data[] = {
-        1,  // type 1 = SOLICIT
-        0xca, 0xfe, 0x01, // trans-id = 0xcafe01
-        0, 1, // option type 1 (client-id)
-        0, 10, // option lenth 10
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // DUID
-        0, 3, // option type 3 (IA_NA)
-        0, 12, // option length 12
-        0, 0, 0, 1, // iaid = 1
-        0, 0, 0, 0, // T1 = 0
-        0, 0, 0, 0  // T2 = 0
-    };
-
-    pkt = new Pkt6(data, sizeof(data));
-    pkt->setRemotePort(546);
-    pkt->setRemoteAddr(IOAddress("fe80::1"));
-    pkt->setLocalPort(0);
-    pkt->setLocalAddr(IOAddress("ff02::1:2"));
-    pkt->setIndex(2);
-    pkt->setIface("eth0");
-
-    return (pkt);
-}
-
-/// @brief a class dedicated to Hooks testing in DHCPv6 server
-///
-/// This class has a number of static members, because each non-static
-/// method has implicit 'this' parameter, so it does not match callout
-/// signature and couldn't be registered. Furthermore, static methods
-/// can't modify non-static members (for obvious reasons), so many
-/// fields are declared static. It is still better to keep them as
-/// one class rather than unrelated collection of global objects.
-class HooksDhcpv6SrvTest : public Dhcpv6SrvTest {
-
-public:
-
-    /// @brief creates Dhcpv6Srv and prepares buffers for callouts
-    HooksDhcpv6SrvTest() {
-
-        // Allocate new DHCPv6 Server
-        srv_ = new NakedDhcpv6Srv(0);
-
-        // clear static buffers
-        resetCalloutBuffers();
-    }
-
-    /// @brief destructor (deletes Dhcpv6Srv)
-    ~HooksDhcpv6SrvTest() {
-        delete srv_;
-    }
-
-    /// @brief creates an option with specified option code
-    ///
-    /// This method is static, because it is used from callouts
-    /// that do not have a pointer to HooksDhcpv6SSrvTest object
-    ///
-    /// @param option_code code of option to be created
-    ///
-    /// @return pointer to create option object
-    static OptionPtr createOption(uint16_t option_code) {
-
-        char payload[] = {
-            0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
-        };
-
-        OptionBuffer tmp(payload, payload + sizeof(payload));
-        return OptionPtr(new Option(Option::V6, option_code, tmp));
-    }
-
-    /// test callback that stores received callout name and pkt6 value
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_receive_callout(CalloutHandle& callout_handle) {
-        callback_name_ = string("pkt6_receive");
-
-        callout_handle.getArgument("query6", callback_pkt6_);
-
-        callback_argument_names_ = callout_handle.getArgumentNames();
-        return (0);
-    }
-
-    /// test callback that changes client-id value
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
-
-        Pkt6Ptr pkt;
-        callout_handle.getArgument("query6", pkt);
-
-        // get rid of the old client-id
-        pkt->delOption(D6O_CLIENTID);
-
-        // add a new option
-        pkt->addOption(createOption(D6O_CLIENTID));
-
-        // carry on as usual
-        return pkt6_receive_callout(callout_handle);
-    }
-
-    /// test callback that deletes client-id
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
-
-        Pkt6Ptr pkt;
-        callout_handle.getArgument("query6", pkt);
-
-        // get rid of the old client-id
-        pkt->delOption(D6O_CLIENTID);
-
-        // carry on as usual
-        return pkt6_receive_callout(callout_handle);
-    }
-
-    /// test callback that sets skip flag
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_receive_skip(CalloutHandle& callout_handle) {
-
-        Pkt6Ptr pkt;
-        callout_handle.getArgument("query6", pkt);
-
-        callout_handle.setSkip(true);
-
-        // carry on as usual
-        return pkt6_receive_callout(callout_handle);
-    }
-
-    /// Test callback that stores received callout name and pkt6 value
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_send_callout(CalloutHandle& callout_handle) {
-        callback_name_ = string("pkt6_send");
-
-        callout_handle.getArgument("response6", callback_pkt6_);
-
-        callback_argument_names_ = callout_handle.getArgumentNames();
-        return (0);
-    }
-
-    // Test callback that changes server-id
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_send_change_serverid(CalloutHandle& callout_handle) {
-
-        Pkt6Ptr pkt;
-        callout_handle.getArgument("response6", pkt);
-
-        // get rid of the old server-id
-        pkt->delOption(D6O_SERVERID);
-
-        // add a new option
-        pkt->addOption(createOption(D6O_SERVERID));
-
-        // carry on as usual
-        return pkt6_send_callout(callout_handle);
-    }
-
-    /// test callback that deletes server-id
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_send_delete_serverid(CalloutHandle& callout_handle) {
-
-        Pkt6Ptr pkt;
-        callout_handle.getArgument("response6", pkt);
-
-        // get rid of the old client-id
-        pkt->delOption(D6O_SERVERID);
-
-        // carry on as usual
-        return pkt6_send_callout(callout_handle);
-    }
-
-    /// Test callback that sets skip flag
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    pkt6_send_skip(CalloutHandle& callout_handle) {
-
-        Pkt6Ptr pkt;
-        callout_handle.getArgument("response6", pkt);
-
-        callout_handle.setSkip(true);
-
-        // carry on as usual
-        return pkt6_send_callout(callout_handle);
-    }
-
-    /// Test callback that stores received callout name and subnet6 values
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    subnet6_select_callout(CalloutHandle& callout_handle) {
-        callback_name_ = string("subnet6_select");
-
-        callout_handle.getArgument("query6", callback_pkt6_);
-        callout_handle.getArgument("subnet6", callback_subnet6_);
-        callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
-
-        callback_argument_names_ = callout_handle.getArgumentNames();
-        return (0);
-    }
-
-    /// Test callback that picks the other subnet if possible.
-    /// @param callout_handle handle passed by the hooks framework
-    /// @return always 0
-    static int
-    subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
-
-        // Call the basic calllout to record all passed values
-        subnet6_select_callout(callout_handle);
-
-        const Subnet6Collection* subnets;
-        Subnet6Ptr subnet;
-        callout_handle.getArgument("subnet6", subnet);
-        callout_handle.getArgument("subnet6collection", subnets);
-
-        // Let's change to a different subnet
-        if (subnets->size() > 1) {
-            subnet = (*subnets)[1]; // Let's pick the other subnet
-            callout_handle.setArgument("subnet6", subnet);
-        }
-
-        return (0);
-    }
-
-    /// resets buffers used to store data received by callouts
-    void resetCalloutBuffers() {
-        callback_name_ = string("");
-        callback_pkt6_.reset();
-        callback_subnet6_.reset();
-        callback_subnet6collection_ = NULL;
-        callback_argument_names_.clear();
-    }
-
-    /// pointer to Dhcpv6Srv that is used in tests
-    NakedDhcpv6Srv* srv_;
-
-    // The following fields are used in testing pkt6_receive_callout
-
-    /// String name of the received callout
-    static string callback_name_;
-
-    /// Pkt6 structure returned in the callout
-    static Pkt6Ptr callback_pkt6_;
-
-    /// Pointer to a subnet received by callout
-    static Subnet6Ptr callback_subnet6_;
-
-    /// A list of all available subnets (received by callout)
-    static const Subnet6Collection* callback_subnet6collection_;
-
-    /// A list of all received arguments
-    static vector<string> callback_argument_names_;
-};
-
-// The following fields are used in testing pkt6_receive_callout.
-// See fields description in the class for details
-string HooksDhcpv6SrvTest::callback_name_;
-Pkt6Ptr HooksDhcpv6SrvTest::callback_pkt6_;
-Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
-const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
-vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
-
-
-// Checks if callouts installed on pkt6_received are indeed called and the
-// all necessary parameters are passed.
-//
-// Note that the test name does not follow test naming convention,
-// but the proper hook name is "pkt6_receive".
-TEST_F(HooksDhcpv6SrvTest, simple_pkt6_receive) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_receive", pkt6_receive_callout));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // check that the callback called is indeed the one we installed
-    EXPECT_EQ("pkt6_receive", callback_name_);
-
-    // check that pkt6 argument passing was successful and returned proper value
-    EXPECT_TRUE(callback_pkt6_.get() == sol.get());
-
-    // Check that all expected parameters are there
-    vector<string> expected_argument_names;
-    expected_argument_names.push_back(string("query6"));
-
-    EXPECT_TRUE(expected_argument_names == callback_argument_names_);
-}
-
-// Checks if callouts installed on pkt6_received is able to change
-// the values and the parameters are indeed used by the server.
-TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_receive) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_receive", pkt6_receive_change_clientid));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // check that the server did send a reposonce
-    ASSERT_EQ(1, srv_->fake_sent_.size());
-
-    // Make sure that we received a response
-    Pkt6Ptr adv = srv_->fake_sent_.front();
-    ASSERT_TRUE(adv);
-
-    // Get client-id...
-    OptionPtr clientid = adv->getOption(D6O_CLIENTID);
-
-    // ... and check if it is the modified value
-    OptionPtr expected = createOption(D6O_CLIENTID);
-    EXPECT_TRUE(clientid->equal(expected));
-}
-
-// Checks if callouts installed on pkt6_received is able to delete
-// existing options and that change impacts server processing (mandatory
-// client-id option is deleted, so the packet is expected to be dropped)
-TEST_F(HooksDhcpv6SrvTest, deleteClientId_pkt6_receive) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_receive", pkt6_receive_delete_clientid));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // Check that the server dropped the packet and did not send a response
-    ASSERT_EQ(0, srv_->fake_sent_.size());
-}
-
-// Checks if callouts installed on pkt6_received is able to set skip flag that
-// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, skip_pkt6_receive) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_receive", pkt6_receive_skip));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // check that the server dropped the packet and did not produce any response
-    ASSERT_EQ(0, srv_->fake_sent_.size());
-}
-
-
-// Checks if callouts installed on pkt6_send are indeed called and the
-// all necessary parameters are passed.
-TEST_F(HooksDhcpv6SrvTest, simple_pkt6_send) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_send", pkt6_send_callout));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // Check that the callback called is indeed the one we installed
-    EXPECT_EQ("pkt6_send", callback_name_);
-
-    // Check that there is one packet sent
-    ASSERT_EQ(1, srv_->fake_sent_.size());
-    Pkt6Ptr adv = srv_->fake_sent_.front();
-
-    // Check that pkt6 argument passing was successful and returned proper value
-    EXPECT_TRUE(callback_pkt6_.get() == adv.get());
-
-    // Check that all expected parameters are there
-    vector<string> expected_argument_names;
-    expected_argument_names.push_back(string("response6"));
-    EXPECT_TRUE(expected_argument_names == callback_argument_names_);
-}
-
-// Checks if callouts installed on pkt6_send is able to change
-// the values and the packet sent contains those changes
-TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_send) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_send", pkt6_send_change_serverid));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // check that the server did send a reposonce
-    ASSERT_EQ(1, srv_->fake_sent_.size());
-
-    // Make sure that we received a response
-    Pkt6Ptr adv = srv_->fake_sent_.front();
-    ASSERT_TRUE(adv);
-
-    // Get client-id...
-    OptionPtr clientid = adv->getOption(D6O_SERVERID);
-
-    // ... and check if it is the modified value
-    OptionPtr expected = createOption(D6O_SERVERID);
-    EXPECT_TRUE(clientid->equal(expected));
-}
-
-// Checks if callouts installed on pkt6_send is able to delete
-// existing options and that server applies those changes. In particular,
-// we are trying to send a packet without server-id. The packet should
-// be sent
-TEST_F(HooksDhcpv6SrvTest, deleteServerId_pkt6_send) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_send", pkt6_send_delete_serverid));
-
-    // Let's create a simple SOLICIT
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // Check that the server indeed sent a malformed ADVERTISE
-    ASSERT_EQ(1, srv_->fake_sent_.size());
-
-    // Get that ADVERTISE
-    Pkt6Ptr adv = srv_->fake_sent_.front();
-    ASSERT_TRUE(adv);
-
-    // Make sure that it does not have server-id
-    EXPECT_FALSE(adv->getOption(D6O_SERVERID));
-}
-
-// Checks if callouts installed on pkt6_skip is able to set skip flag that
-// will cause the server to not process the packet (drop), even though it is valid.
-TEST_F(HooksDhcpv6SrvTest, skip_pkt6_send) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "pkt6_send", pkt6_send_skip));
-
-    // Let's create a simple REQUEST
-    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
-
-    // Simulate that we have received that traffic
-    srv_->fakeReceive(sol);
-
-    // Server will now process to run its normal loop, but instead of calling
-    // IfaceMgr::receive6(), it will read all packets from the list set by
-    // fakeReceive()
-    // In particular, it should call registered pkt6_receive callback.
-    srv_->run();
-
-    // check that the server dropped the packet and did not produce any response
-    ASSERT_EQ(0, srv_->fake_sent_.size());
-}
-
-// This test checks if subnet6_select callout is triggered and reports
-// valid parameters
-TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "subnet6_select", subnet6_select_callout));
-
-    // Configure 2 subnets, both directly reachable over local interface
-    // (let's not complicate the matter with relays)
-    string config = "{ \"interfaces\": [ \"*\" ],"
-        "\"preferred-lifetime\": 3000,"
-        "\"rebind-timer\": 2000, "
-        "\"renew-timer\": 1000, "
-        "\"subnet6\": [ { "
-        "    \"pool\": [ \"2001:db8:1::/64\" ],"
-        "    \"subnet\": \"2001:db8:1::/48\", "
-        "    \"interface\": \"" + valid_iface_ + "\" "
-        " }, {"
-        "    \"pool\": [ \"2001:db8:2::/64\" ],"
-        "    \"subnet\": \"2001:db8:2::/48\" "
-        " } ],"
-        "\"valid-lifetime\": 4000 }";
-
-    ElementPtr json = Element::fromJSON(config);
-    ConstElementPtr status;
-
-    // Configure the server and make sure the config is accepted
-    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
-    ASSERT_TRUE(status);
-    comment_ = parseAnswer(rcode_, status);
-    ASSERT_EQ(0, rcode_);
-
-    // Prepare solicit packet. Server should select first subnet for it
-    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
-    sol->setRemoteAddr(IOAddress("fe80::abcd"));
-    sol->setIface(valid_iface_);
-    sol->addOption(generateIA(234, 1500, 3000));
-    OptionPtr clientid = generateClientId();
-    sol->addOption(clientid);
-
-    // Pass it to the server and get an advertise
-    Pkt6Ptr adv = srv_->processSolicit(sol);
-
-    // check if we get response at all
-    ASSERT_TRUE(adv);
-
-    // Check that the callback called is indeed the one we installed
-    EXPECT_EQ("subnet6_select", callback_name_);
-
-    // Check that pkt6 argument passing was successful and returned proper value
-    EXPECT_TRUE(callback_pkt6_.get() == sol.get());
-
-    const Subnet6Collection* exp_subnets = CfgMgr::instance().getSubnets6();
-
-    // The server is supposed to pick the first subnet, because of matching
-    // interface. Check that the value is reported properly.
-    ASSERT_TRUE(callback_subnet6_);
-    EXPECT_EQ(callback_subnet6_.get(), exp_subnets->front().get());
-
-    // Server is supposed to report two subnets
-    ASSERT_EQ(exp_subnets->size(), callback_subnet6collection_->size());
-
-    // Compare that the available subnets are reported as expected
-    EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet6collection_)[0].get());
-    EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet6collection_)[1].get());
-}
-
-// This test checks if callout installed on subnet6_select hook point can pick
-// a different subnet.
-TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
-
-    // Install pkt6_receive_callout
-    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
-                        "subnet6_select", subnet6_select_different_subnet_callout));
-
-    // Configure 2 subnets, both directly reachable over local interface
-    // (let's not complicate the matter with relays)
-    string config = "{ \"interfaces\": [ \"*\" ],"
-        "\"preferred-lifetime\": 3000,"
-        "\"rebind-timer\": 2000, "
-        "\"renew-timer\": 1000, "
-        "\"subnet6\": [ { "
-        "    \"pool\": [ \"2001:db8:1::/64\" ],"
-        "    \"subnet\": \"2001:db8:1::/48\", "
-        "    \"interface\": \"" + valid_iface_ + "\" "
-        " }, {"
-        "    \"pool\": [ \"2001:db8:2::/64\" ],"
-        "    \"subnet\": \"2001:db8:2::/48\" "
-        " } ],"
-        "\"valid-lifetime\": 4000 }";
-
-    ElementPtr json = Element::fromJSON(config);
-    ConstElementPtr status;
-
-    // Configure the server and make sure the config is accepted
-    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
-    ASSERT_TRUE(status);
-    comment_ = parseAnswer(rcode_, status);
-    ASSERT_EQ(0, rcode_);
-
-    // Prepare solicit packet. Server should select first subnet for it
-    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
-    sol->setRemoteAddr(IOAddress("fe80::abcd"));
-    sol->setIface(valid_iface_);
-    sol->addOption(generateIA(234, 1500, 3000));
-    OptionPtr clientid = generateClientId();
-    sol->addOption(clientid);
-
-    // Pass it to the server and get an advertise
-    Pkt6Ptr adv = srv_->processSolicit(sol);
-
-    // check if we get response at all
-    ASSERT_TRUE(adv);
-
-    // The response should have an address from second pool, so let's check it
-    OptionPtr tmp = adv->getOption(D6O_IA_NA);
-    ASSERT_TRUE(tmp);
-    boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
-    ASSERT_TRUE(ia);
-    tmp = ia->getOption(D6O_IAADDR);
-    ASSERT_TRUE(tmp);
-    boost::shared_ptr<Option6IAAddr> addr_opt =
-        boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
-    ASSERT_TRUE(addr_opt);
-
-    // Get all subnets and use second subnet for verification
-    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
-    ASSERT_EQ(2, subnets->size());
-
-    // Advertised address must belong to the second pool (in subnet's range,
-    // in dynamic pool)
-    EXPECT_TRUE((*subnets)[1]->inRange(addr_opt->getAddress()));
-    EXPECT_TRUE((*subnets)[1]->inPool(addr_opt->getAddress()));
-}
-
-
 /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
 /// to call processX() methods.
 
diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h
new file mode 100644
index 0000000..0436b59
--- /dev/null
+++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h
@@ -0,0 +1,403 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// @file   dhcp6_test_utils.h
+///
+/// @brief  This file contains utility classes used for DHCPv6 server testing
+
+#include <gtest/gtest.h>
+
+#include <dhcp/pkt6.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option_int_array.h>
+#include <dhcp/option_custom.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <hooks/hooks_manager.h>
+#include <config/ccsession.h>
+
+#include <list>
+
+using namespace isc::dhcp;
+using namespace isc::config;
+using namespace isc::data;
+using namespace isc::hooks;
+using namespace isc::asiolink;
+using namespace isc::util;
+using namespace isc::hooks;
+
+namespace isc {
+namespace test {
+
+/// @brief "naked" Dhcpv6Srv class that exposes internal members
+class NakedDhcpv6Srv: public isc::dhcp::Dhcpv6Srv {
+public:
+    NakedDhcpv6Srv(uint16_t port) : Dhcpv6Srv(port) {
+        // Open the "memfile" database for leases
+        std::string memfile = "type=memfile";
+        LeaseMgrFactory::create(memfile);
+    }
+
+    /// @brief fakes packet reception
+    /// @param timeout ignored
+    ///
+    /// The method receives all packets queued in receive
+    /// queue, one after another. Once the queue is empty,
+    /// it initiates the shutdown procedure.
+    ///
+    /// See fake_received_ field for description
+    virtual isc::dhcp::Pkt6Ptr receivePacket(int /*timeout*/) {
+
+        // If there is anything prepared as fake incoming
+        // traffic, use it
+        if (!fake_received_.empty()) {
+            Pkt6Ptr pkt = fake_received_.front();
+            fake_received_.pop_front();
+            return (pkt);
+        }
+
+        // If not, just trigger shutdown and
+        // return immediately
+        shutdown();
+        return (Pkt6Ptr());
+    }
+
+    /// @brief fake packet sending
+    ///
+    /// Pretend to send a packet, but instead just store
+    /// it in fake_send_ list where test can later inspect
+    /// server's response.
+    virtual void sendPacket(const Pkt6Ptr& pkt) {
+        fake_sent_.push_back(pkt);
+    }
+
+    /// @brief adds a packet to fake receive queue
+    ///
+    /// See fake_received_ field for description
+    void fakeReceive(const Pkt6Ptr& pkt) {
+        fake_received_.push_back(pkt);
+    }
+
+    virtual ~NakedDhcpv6Srv() {
+        // Close the lease database
+        LeaseMgrFactory::destroy();
+    }
+
+    using Dhcpv6Srv::processSolicit;
+    using Dhcpv6Srv::processRequest;
+    using Dhcpv6Srv::processRenew;
+    using Dhcpv6Srv::processRelease;
+    using Dhcpv6Srv::createStatusCode;
+    using Dhcpv6Srv::selectSubnet;
+    using Dhcpv6Srv::sanityCheck;
+    using Dhcpv6Srv::loadServerID;
+    using Dhcpv6Srv::writeServerID;
+
+    /// @brief packets we pretend to receive
+    ///
+    /// Instead of setting up sockets on interfaces that change between OSes, it
+    /// is much easier to fake packet reception. This is a list of packets that
+    /// we pretend to have received. You can schedule new packets to be received
+    /// using fakeReceive() and NakedDhcpv6Srv::receivePacket() methods.
+    std::list<Pkt6Ptr> fake_received_;
+
+    std::list<Pkt6Ptr> fake_sent_;
+};
+
+static const char* DUID_FILE = "server-id-test.txt";
+
+// test fixture for any tests requiring blank/empty configuration
+// serves as base class for additional tests
+class NakedDhcpv6SrvTest : public ::testing::Test {
+public:
+
+    NakedDhcpv6SrvTest() : rcode_(-1) {
+        // it's ok if that fails. There should not be such a file anyway
+        unlink(DUID_FILE);
+
+        const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+        // There must be some interface detected
+        if (ifaces.empty()) {
+            // We can't use ASSERT in constructor
+            ADD_FAILURE() << "No interfaces detected.";
+        }
+
+        valid_iface_ = ifaces.begin()->getName();
+    }
+
+    // Generate IA_NA option with specified parameters
+    boost::shared_ptr<Option6IA> generateIA(uint32_t iaid, uint32_t t1, uint32_t t2) {
+        boost::shared_ptr<Option6IA> ia =
+            boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, iaid));
+        ia->setT1(t1);
+        ia->setT2(t2);
+        return (ia);
+    }
+
+    /// @brief generates interface-id option, based on text
+    ///
+    /// @param iface_id textual representation of the interface-id content
+    ///
+    /// @return pointer to the option object
+    OptionPtr generateInterfaceId(const std::string& iface_id) {
+        OptionBuffer tmp(iface_id.begin(), iface_id.end());
+        return OptionPtr(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
+    }
+
+    // Generate client-id option
+    OptionPtr generateClientId(size_t duid_size = 32) {
+
+        OptionBuffer clnt_duid(duid_size);
+        for (int i = 0; i < duid_size; i++) {
+            clnt_duid[i] = 100 + i;
+        }
+
+        duid_ = DuidPtr(new DUID(clnt_duid));
+
+        return (OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                     clnt_duid.begin(),
+                                     clnt_duid.begin() + duid_size)));
+    }
+
+    // Checks if server response (ADVERTISE or REPLY) includes proper server-id.
+    void checkServerId(const Pkt6Ptr& rsp, const OptionPtr& expected_srvid) {
+        // check that server included its server-id
+        OptionPtr tmp = rsp->getOption(D6O_SERVERID);
+        EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
+        ASSERT_EQ(tmp->len(), expected_srvid->len() );
+        EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
+    }
+
+    // Checks if server response (ADVERTISE or REPLY) includes proper client-id.
+    void checkClientId(const Pkt6Ptr& rsp, const OptionPtr& expected_clientid) {
+        // check that server included our own client-id
+        OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
+        ASSERT_TRUE(tmp);
+        EXPECT_EQ(expected_clientid->getType(), tmp->getType());
+        ASSERT_EQ(expected_clientid->len(), tmp->len());
+
+        // check that returned client-id is valid
+        EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
+    }
+
+    // Checks if server response is a NAK
+    void checkNakResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
+                          uint32_t expected_transid,
+                          uint16_t expected_status_code) {
+        // Check if we get response at all
+        checkResponse(rsp, expected_message_type, expected_transid);
+
+        // Check that IA_NA was returned
+        OptionPtr option_ia_na = rsp->getOption(D6O_IA_NA);
+        ASSERT_TRUE(option_ia_na);
+
+        // check that the status is no address available
+        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(option_ia_na);
+        ASSERT_TRUE(ia);
+
+        checkIA_NAStatusCode(ia, expected_status_code);
+    }
+
+    // Checks that server rejected IA_NA, i.e. that it has no addresses and
+    // that expected status code really appears there. In some limited cases
+    // (reply to RELEASE) it may be used to verify positive case, where
+    // IA_NA response is expected to not include address.
+    //
+    // Status code indicates type of error encountered (in theory it can also
+    // indicate success, but servers typically don't send success status
+    // as this is the default result and it saves bandwidth)
+    void checkIA_NAStatusCode(const boost::shared_ptr<Option6IA>& ia,
+                            uint16_t expected_status_code) {
+        // Make sure there is no address assigned.
+        EXPECT_FALSE(ia->getOption(D6O_IAADDR));
+
+        // T1, T2 should be zeroed
+        EXPECT_EQ(0, ia->getT1());
+        EXPECT_EQ(0, ia->getT2());
+
+        OptionCustomPtr status =
+            boost::dynamic_pointer_cast<OptionCustom>(ia->getOption(D6O_STATUS_CODE));
+
+        // It is ok to not include status success as this is the default behavior
+        if (expected_status_code == STATUS_Success && !status) {
+            return;
+        }
+
+        EXPECT_TRUE(status);
+
+        if (status) {
+            // We don't have dedicated class for status code, so let's just interpret
+            // first 2 bytes as status. Remainder of the status code option content is
+            // just a text explanation what went wrong.
+            EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
+                      status->readInteger<uint16_t>(0));
+        }
+    }
+
+    void checkMsgStatusCode(const Pkt6Ptr& msg, uint16_t expected_status) {
+        OptionCustomPtr status =
+            boost::dynamic_pointer_cast<OptionCustom>(msg->getOption(D6O_STATUS_CODE));
+
+        // It is ok to not include status success as this is the default behavior
+        if (expected_status == STATUS_Success && !status) {
+            return;
+        }
+
+        EXPECT_TRUE(status);
+        if (status) {
+            // We don't have dedicated class for status code, so let's just interpret
+            // first 2 bytes as status. Remainder of the status code option content is
+            // just a text explanation what went wrong.
+            EXPECT_EQ(static_cast<uint16_t>(expected_status),
+                      status->readInteger<uint16_t>(0));
+        }
+    }
+
+    // Basic checks for generated response (message type and transaction-id).
+    void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
+                       uint32_t expected_transid) {
+        ASSERT_TRUE(rsp);
+        EXPECT_EQ(expected_message_type, rsp->getType());
+        EXPECT_EQ(expected_transid, rsp->getTransid());
+    }
+
+    virtual ~NakedDhcpv6SrvTest() {
+        // Let's clean up if there is such a file.
+        unlink(DUID_FILE);
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "buffer6_receive");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "buffer6_send");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "lease6_renew");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "lease6_release");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "pkt6_receive");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "pkt6_send");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+                                                 "subnet6_select");
+
+    };
+
+    // A DUID used in most tests (typically as client-id)
+    DuidPtr duid_;
+
+    int rcode_;
+    ConstElementPtr comment_;
+
+    // Name of a valid network interface
+    std::string valid_iface_;
+};
+
+// Provides suport for tests against a preconfigured subnet6
+// extends upon NakedDhcp6SrvTest
+class Dhcpv6SrvTest : public NakedDhcpv6SrvTest {
+public:
+    /// Name of the server-id file (used in server-id tests)
+
+    // these are empty for now, but let's keep them around
+    Dhcpv6SrvTest() {
+        subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
+                                         2000, 3000, 4000));
+        pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+        subnet_->addPool(pool_);
+
+        CfgMgr::instance().deleteSubnets6();
+        CfgMgr::instance().addSubnet6(subnet_);
+    }
+
+    // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
+    // It returns IAADDR option for each chaining with checkIAAddr method.
+    boost::shared_ptr<Option6IAAddr> checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
+                                            uint32_t expected_t1, uint32_t expected_t2) {
+        OptionPtr tmp = rsp->getOption(D6O_IA_NA);
+        // Can't use ASSERT_TRUE() in method that returns something
+        if (!tmp) {
+            ADD_FAILURE() << "IA_NA option not present in response";
+            return (boost::shared_ptr<Option6IAAddr>());
+        }
+
+        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+        if (!ia) {
+            ADD_FAILURE() << "IA_NA cannot convert option ptr to Option6";
+            return (boost::shared_ptr<Option6IAAddr>());
+        }
+
+        EXPECT_EQ(expected_iaid, ia->getIAID());
+        EXPECT_EQ(expected_t1, ia->getT1());
+        EXPECT_EQ(expected_t2, ia->getT2());
+
+        tmp = ia->getOption(D6O_IAADDR);
+        boost::shared_ptr<Option6IAAddr> addr = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
+        return (addr);
+    }
+
+    // Check that generated IAADDR option contains expected address
+    // and lifetime values match the configured subnet
+    void checkIAAddr(const boost::shared_ptr<Option6IAAddr>& addr,
+                     const IOAddress& expected_addr,
+                     uint32_t /* expected_preferred */,
+                     uint32_t /* expected_valid */) {
+
+        // Check that the assigned address is indeed from the configured pool.
+        // Note that when comparing addresses, we compare the textual
+        // representation. IOAddress does not support being streamed to
+        // an ostream, which means it can't be used in EXPECT_EQ.
+        EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
+        EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
+        EXPECT_EQ(addr->getPreferred(), subnet_->getPreferred());
+        EXPECT_EQ(addr->getValid(), subnet_->getValid());
+    }
+
+    // Checks if the lease sent to client is present in the database
+    // and is valid when checked agasint the configured subnet
+    Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
+                         boost::shared_ptr<Option6IAAddr> addr) {
+        boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(ia_na);
+
+        Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(addr->getAddress());
+        if (!lease) {
+            std::cout << "Lease for " << addr->getAddress().toText()
+                      << " not found in the database backend.";
+            return (Lease6Ptr());
+        }
+
+        EXPECT_EQ(addr->getAddress().toText(), lease->addr_.toText());
+        EXPECT_TRUE(*lease->duid_ == *duid);
+        EXPECT_EQ(ia->getIAID(), lease->iaid_);
+        EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
+
+        return (lease);
+    }
+
+    ~Dhcpv6SrvTest() {
+        CfgMgr::instance().deleteSubnets6();
+    };
+
+    /// A subnet used in most tests
+    Subnet6Ptr subnet_;
+
+    /// A pool used in most tests
+    Pool6Ptr pool_;
+};
+
+}; // end of isc::test namespace
+}; // end of isc namespace
diff --git a/src/bin/dhcp6/tests/hooks_unittest.cc b/src/bin/dhcp6/tests/hooks_unittest.cc
new file mode 100644
index 0000000..717de08
--- /dev/null
+++ b/src/bin/dhcp6/tests/hooks_unittest.cc
@@ -0,0 +1,1457 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/duid.h>
+#include <dhcp6/config_parser.h>
+#include <dhcp/dhcp6.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/utils.h>
+#include <util/buffer.h>
+#include <util/range_utilities.h>
+#include <hooks/server_hooks.h>
+
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+using namespace isc;
+using namespace isc::test;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace isc::hooks;
+using namespace std;
+
+// namespace has to be named, because friends are defined in Dhcpv6Srv class
+// Maybe it should be isc::test?
+namespace {
+
+// Checks if hooks are implemented properly.
+TEST_F(Dhcpv6SrvTest, Hooks) {
+    NakedDhcpv6Srv srv(0);
+
+    // check if appropriate hooks are registered
+    int hook_index_buffer6_receive = -1;
+    int hook_index_buffer6_send    = -1;
+    int hook_index_lease6_renew    = -1;
+    int hook_index_lease6_release  = -1;
+    int hook_index_pkt6_received   = -1;
+    int hook_index_select_subnet   = -1;
+    int hook_index_pkt6_send       = -1;
+
+    // check if appropriate indexes are set
+    EXPECT_NO_THROW(hook_index_buffer6_receive = ServerHooks::getServerHooks()
+                    .getIndex("buffer6_receive"));
+    EXPECT_NO_THROW(hook_index_buffer6_send = ServerHooks::getServerHooks()
+                    .getIndex("buffer6_send"));
+    EXPECT_NO_THROW(hook_index_lease6_renew = ServerHooks::getServerHooks()
+                    .getIndex("lease6_renew"));
+    EXPECT_NO_THROW(hook_index_lease6_release = ServerHooks::getServerHooks()
+                    .getIndex("lease6_release"));
+    EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
+                    .getIndex("pkt6_receive"));
+    EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
+                    .getIndex("subnet6_select"));
+    EXPECT_NO_THROW(hook_index_pkt6_send     = ServerHooks::getServerHooks()
+                    .getIndex("pkt6_send"));
+
+    EXPECT_TRUE(hook_index_pkt6_received   > 0);
+    EXPECT_TRUE(hook_index_select_subnet   > 0);
+    EXPECT_TRUE(hook_index_pkt6_send       > 0);
+    EXPECT_TRUE(hook_index_buffer6_receive > 0);
+    EXPECT_TRUE(hook_index_buffer6_send    > 0);
+    EXPECT_TRUE(hook_index_lease6_renew    > 0);
+    EXPECT_TRUE(hook_index_lease6_release  > 0);
+}
+
+// This function returns buffer for very simple Solicit
+Pkt6* captureSimpleSolicit() {
+    Pkt6* pkt;
+    uint8_t data[] = {
+        1,  // type 1 = SOLICIT
+        0xca, 0xfe, 0x01, // trans-id = 0xcafe01
+        0, 1, // option type 1 (client-id)
+        0, 10, // option lenth 10
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // DUID
+        0, 3, // option type 3 (IA_NA)
+        0, 12, // option length 12
+        0, 0, 0, 1, // iaid = 1
+        0, 0, 0, 0, // T1 = 0
+        0, 0, 0, 0  // T2 = 0
+    };
+
+    pkt = new Pkt6(data, sizeof(data));
+    pkt->setRemotePort(546);
+    pkt->setRemoteAddr(IOAddress("fe80::1"));
+    pkt->setLocalPort(0);
+    pkt->setLocalAddr(IOAddress("ff02::1:2"));
+    pkt->setIndex(2);
+    pkt->setIface("eth0");
+
+    return (pkt);
+}
+
+/// @brief a class dedicated to Hooks testing in DHCPv6 server
+///
+/// This class has a number of static members, because each non-static
+/// method has implicit 'this' parameter, so it does not match callout
+/// signature and couldn't be registered. Furthermore, static methods
+/// can't modify non-static members (for obvious reasons), so many
+/// fields are declared static. It is still better to keep them as
+/// one class rather than unrelated collection of global objects.
+class HooksDhcpv6SrvTest : public Dhcpv6SrvTest {
+
+public:
+
+    /// @brief creates Dhcpv6Srv and prepares buffers for callouts
+    HooksDhcpv6SrvTest() {
+
+        // Allocate new DHCPv6 Server
+        srv_.reset(new NakedDhcpv6Srv(0));
+
+        // Clear static buffers
+        resetCalloutBuffers();
+    }
+
+    /// @brief destructor (deletes Dhcpv6Srv)
+    ~HooksDhcpv6SrvTest() {
+    }
+
+    /// @brief creates an option with specified option code
+    ///
+    /// This method is static, because it is used from callouts
+    /// that do not have a pointer to HooksDhcpv6SSrvTest object
+    ///
+    /// @param option_code code of option to be created
+    ///
+    /// @return pointer to create option object
+    static OptionPtr createOption(uint16_t option_code) {
+
+        uint8_t payload[] = {
+            0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
+        };
+
+        OptionBuffer tmp(payload, payload + sizeof(payload));
+        return OptionPtr(new Option(Option::V6, option_code, tmp));
+    }
+
+    /// test callback that stores received callout name and pkt6 value
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_receive_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("pkt6_receive");
+
+        callout_handle.getArgument("query6", callback_pkt6_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// test callback that changes client-id value
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("query6", pkt);
+
+        // Get rid of the old client-id
+        pkt->delOption(D6O_CLIENTID);
+
+        // Add a new option
+        pkt->addOption(createOption(D6O_CLIENTID));
+
+        // Carry on as usual
+        return pkt6_receive_callout(callout_handle);
+    }
+
+    /// Test callback that deletes client-id
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("query6", pkt);
+
+        // Get rid of the old client-id
+        pkt->delOption(D6O_CLIENTID);
+
+        // Carry on as usual
+        return pkt6_receive_callout(callout_handle);
+    }
+
+    /// Test callback that sets skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_receive_skip(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("query6", pkt);
+
+        callout_handle.setSkip(true);
+
+        // Carry on as usual
+        return pkt6_receive_callout(callout_handle);
+    }
+
+    /// Test callback that stores received callout name and pkt6 value
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    buffer6_receive_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("buffer6_receive");
+
+        callout_handle.getArgument("query6", callback_pkt6_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// Test callback that changes first byte of client-id value
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    buffer6_receive_change_clientid(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("query6", pkt);
+
+        // If there is at least one option with data
+        if (pkt->data_.size() > Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN) {
+            // Offset of the first byte of the first option. Let's set this byte
+            // to some new value that we could later check
+            pkt->data_[Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN] = 0xff;
+        }
+
+        // Carry on as usual
+        return buffer6_receive_callout(callout_handle);
+    }
+
+    /// Test callback that deletes client-id
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    buffer6_receive_delete_clientid(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("query6", pkt);
+
+        // this is modified SOLICIT (with missing mandatory client-id)
+        uint8_t data[] = {
+        1,  // type 1 = SOLICIT
+        0xca, 0xfe, 0x01, // trans-id = 0xcafe01
+        0, 3, // option type 3 (IA_NA)
+        0, 12, // option length 12
+        0, 0, 0, 1, // iaid = 1
+        0, 0, 0, 0, // T1 = 0
+        0, 0, 0, 0  // T2 = 0
+        };
+
+        OptionBuffer modifiedMsg(data, data + sizeof(data));
+
+        pkt->data_ = modifiedMsg;
+
+        // carry on as usual
+        return buffer6_receive_callout(callout_handle);
+    }
+
+    /// Test callback that sets skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    buffer6_receive_skip(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("query6", pkt);
+
+        callout_handle.setSkip(true);
+
+        // Carry on as usual
+        return buffer6_receive_callout(callout_handle);
+    }
+
+    /// Test callback that stores received callout name and pkt6 value
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_send_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("pkt6_send");
+
+        callout_handle.getArgument("response6", callback_pkt6_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    // Test callback that changes server-id
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_send_change_serverid(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("response6", pkt);
+
+        // Get rid of the old server-id
+        pkt->delOption(D6O_SERVERID);
+
+        // Add a new option
+        pkt->addOption(createOption(D6O_SERVERID));
+
+        // Carry on as usual
+        return pkt6_send_callout(callout_handle);
+    }
+
+    /// Test callback that deletes server-id
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_send_delete_serverid(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("response6", pkt);
+
+        // Get rid of the old client-id
+        pkt->delOption(D6O_SERVERID);
+
+        // Carry on as usual
+        return pkt6_send_callout(callout_handle);
+    }
+
+    /// Test callback that sets skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    pkt6_send_skip(CalloutHandle& callout_handle) {
+
+        Pkt6Ptr pkt;
+        callout_handle.getArgument("response6", pkt);
+
+        callout_handle.setSkip(true);
+
+        // carry on as usual
+        return pkt6_send_callout(callout_handle);
+    }
+
+    /// Test callback that stores received callout name and subnet6 values
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    subnet6_select_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("subnet6_select");
+
+        callout_handle.getArgument("query6", callback_pkt6_);
+        callout_handle.getArgument("subnet6", callback_subnet6_);
+        callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// Test callback that picks the other subnet if possible.
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
+
+        // Call the basic calllout to record all passed values
+        subnet6_select_callout(callout_handle);
+
+        const Subnet6Collection* subnets;
+        Subnet6Ptr subnet;
+        callout_handle.getArgument("subnet6", subnet);
+        callout_handle.getArgument("subnet6collection", subnets);
+
+        // Let's change to a different subnet
+        if (subnets->size() > 1) {
+            subnet = (*subnets)[1]; // Let's pick the other subnet
+            callout_handle.setArgument("subnet6", subnet);
+        }
+
+        return (0);
+    }
+
+    /// Test callback that stores received callout name and pkt6 value
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    lease6_renew_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("lease6_renew");
+
+        callout_handle.getArgument("query6", callback_pkt6_);
+        callout_handle.getArgument("lease6", callback_lease6_);
+        callout_handle.getArgument("ia_na", callback_ia_na_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// The following values are used by the callout to override
+    /// renewed lease parameters
+    static const uint32_t override_iaid_;
+    static const uint32_t override_t1_;
+    static const uint32_t override_t2_;
+    static const uint32_t override_preferred_;
+    static const uint32_t override_valid_;
+
+    /// Test callback that overrides received lease. It updates
+    /// T1, T2, preferred and valid lifetimes
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    lease6_renew_update_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("lease6_renew");
+
+        callout_handle.getArgument("query6", callback_pkt6_);
+        callout_handle.getArgument("lease6", callback_lease6_);
+        callout_handle.getArgument("ia_na", callback_ia_na_);
+
+        // Let's override some values in the lease
+        callback_lease6_->iaid_          = override_iaid_;
+        callback_lease6_->t1_            = override_t1_;
+        callback_lease6_->t2_            = override_t2_;
+        callback_lease6_->preferred_lft_ = override_preferred_;
+        callback_lease6_->valid_lft_     = override_valid_;
+
+        // Override the values to be sent to the client as well
+        callback_ia_na_->setIAID(override_iaid_);
+        callback_ia_na_->setT1(override_t1_);
+        callback_ia_na_->setT2(override_t2_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// Test callback that sets the skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    lease6_renew_skip_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("lease6_renew");
+
+        callout_handle.setSkip(true);
+
+        return (0);
+    }
+
+    /// Test callback that stores received callout name passed parameters
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    lease6_release_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("lease6_release");
+
+        callout_handle.getArgument("query6", callback_pkt6_);
+        callout_handle.getArgument("lease6", callback_lease6_);
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// Test callback that sets the skip flag
+    /// @param callout_handle handle passed by the hooks framework
+    /// @return always 0
+    static int
+    lease6_release_skip_callout(CalloutHandle& callout_handle) {
+        callback_name_ = string("lease6_release");
+
+        callout_handle.setSkip(true);
+
+        return (0);
+    }
+
+    /// Resets buffers used to store data received by callouts
+    void resetCalloutBuffers() {
+        callback_name_ = string("");
+        callback_pkt6_.reset();
+        callback_subnet6_.reset();
+        callback_lease6_.reset();
+        callback_ia_na_.reset();
+        callback_subnet6collection_ = NULL;
+        callback_argument_names_.clear();
+    }
+
+    /// Pointer to Dhcpv6Srv that is used in tests
+    boost::scoped_ptr<NakedDhcpv6Srv> srv_;
+
+    // The following fields are used in testing pkt6_receive_callout
+
+    /// String name of the received callout
+    static string callback_name_;
+
+    /// Pkt6 structure returned in the callout
+    static Pkt6Ptr callback_pkt6_;
+
+    /// Pointer to lease6
+    static Lease6Ptr callback_lease6_;
+
+    /// Pointer to IA_NA option being renewed
+    static boost::shared_ptr<Option6IA> callback_ia_na_;
+
+    /// Pointer to a subnet received by callout
+    static Subnet6Ptr callback_subnet6_;
+
+    /// A list of all available subnets (received by callout)
+    static const Subnet6Collection* callback_subnet6collection_;
+
+    /// A list of all received arguments
+    static vector<string> callback_argument_names_;
+};
+
+// The following parameters are used by callouts to override
+// renewed lease parameters
+const uint32_t HooksDhcpv6SrvTest::override_iaid_ = 1000;
+const uint32_t HooksDhcpv6SrvTest::override_t1_ = 1001;
+const uint32_t HooksDhcpv6SrvTest::override_t2_ = 1002;
+const uint32_t HooksDhcpv6SrvTest::override_preferred_ = 1003;
+const uint32_t HooksDhcpv6SrvTest::override_valid_ = 1004;
+
+// The following fields are used in testing pkt6_receive_callout.
+// See fields description in the class for details
+string HooksDhcpv6SrvTest::callback_name_;
+Pkt6Ptr HooksDhcpv6SrvTest::callback_pkt6_;
+Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
+const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
+vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
+Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
+boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
+
+// Checks if callouts installed on pkt6_receive are indeed called and the
+// all necessary parameters are passed.
+//
+// Note that the test name does not follow test naming convention,
+// but the proper hook name is "buffer6_receive".
+TEST_F(HooksDhcpv6SrvTest, simple_buffer6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_receive", buffer6_receive_callout));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("buffer6_receive", callback_name_);
+
+    // Check that pkt6 argument passing was successful and returned proper value
+    EXPECT_TRUE(callback_pkt6_.get() == sol.get());
+
+    // Check that all expected parameters are there
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back(string("query6"));
+
+    EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+}
+
+// Checks if callouts installed on pkt6_received is able to change
+// the values and the parameters are indeed used by the server.
+TEST_F(HooksDhcpv6SrvTest, valueChange_buffer6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_receive", buffer6_receive_change_clientid));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server did send a reposonce
+    ASSERT_EQ(1, srv_->fake_sent_.size());
+
+    // Make sure that we received a response
+    Pkt6Ptr adv = srv_->fake_sent_.front();
+    ASSERT_TRUE(adv);
+
+    // Get client-id...
+    OptionPtr clientid = adv->getOption(D6O_CLIENTID);
+
+    ASSERT_TRUE(clientid);
+
+    // ... and check if it is the modified value
+    EXPECT_EQ(0xff, clientid->getData()[0]);
+}
+
+// Checks if callouts installed on buffer6_receive is able to delete
+// existing options and that change impacts server processing (mandatory
+// client-id option is deleted, so the packet is expected to be dropped)
+TEST_F(HooksDhcpv6SrvTest, deleteClientId_buffer6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_receive", buffer6_receive_delete_clientid));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server dropped the packet and did not send a response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
+// Checks if callouts installed on buffer6_received is able to set skip flag that
+// will cause the server to not process the packet (drop), even though it is valid.
+TEST_F(HooksDhcpv6SrvTest, skip_buffer6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "buffer6_receive", buffer6_receive_skip));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server dropped the packet and did not produce any response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
+// Checks if callouts installed on pkt6_receive are indeed called and the
+// all necessary parameters are passed.
+//
+// Note that the test name does not follow test naming convention,
+// but the proper hook name is "pkt6_receive".
+TEST_F(HooksDhcpv6SrvTest, simple_pkt6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_receive", pkt6_receive_callout));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("pkt6_receive", callback_name_);
+
+    // Check that pkt6 argument passing was successful and returned proper value
+    EXPECT_TRUE(callback_pkt6_.get() == sol.get());
+
+    // Check that all expected parameters are there
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back(string("query6"));
+
+    EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+}
+
+// Checks if callouts installed on pkt6_received is able to change
+// the values and the parameters are indeed used by the server.
+TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_receive", pkt6_receive_change_clientid));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server did send a reposonce
+    ASSERT_EQ(1, srv_->fake_sent_.size());
+
+    // Make sure that we received a response
+    Pkt6Ptr adv = srv_->fake_sent_.front();
+    ASSERT_TRUE(adv);
+
+    // Get client-id...
+    OptionPtr clientid = adv->getOption(D6O_CLIENTID);
+
+    // ... and check if it is the modified value
+    OptionPtr expected = createOption(D6O_CLIENTID);
+    EXPECT_TRUE(clientid->equal(expected));
+}
+
+// Checks if callouts installed on pkt6_received is able to delete
+// existing options and that change impacts server processing (mandatory
+// client-id option is deleted, so the packet is expected to be dropped)
+TEST_F(HooksDhcpv6SrvTest, deleteClientId_pkt6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_receive", pkt6_receive_delete_clientid));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server dropped the packet and did not send a response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
+// Checks if callouts installed on pkt6_received is able to set skip flag that
+// will cause the server to not process the packet (drop), even though it is valid.
+TEST_F(HooksDhcpv6SrvTest, skip_pkt6_receive) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_receive", pkt6_receive_skip));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server dropped the packet and did not produce any response
+    ASSERT_EQ(0, srv_->fake_sent_.size());
+}
+
+
+// Checks if callouts installed on pkt6_send are indeed called and the
+// all necessary parameters are passed.
+TEST_F(HooksDhcpv6SrvTest, simple_pkt6_send) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_send", pkt6_send_callout));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("pkt6_send", callback_name_);
+
+    // Check that there is one packet sent
+    ASSERT_EQ(1, srv_->fake_sent_.size());
+    Pkt6Ptr adv = srv_->fake_sent_.front();
+
+    // Check that pkt6 argument passing was successful and returned proper value
+    EXPECT_TRUE(callback_pkt6_.get() == adv.get());
+
+    // Check that all expected parameters are there
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back(string("response6"));
+    EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+}
+
+// Checks if callouts installed on pkt6_send is able to change
+// the values and the packet sent contains those changes
+TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_send) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_send", pkt6_send_change_serverid));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server did send a response
+    ASSERT_EQ(1, srv_->fake_sent_.size());
+
+    // Make sure that we received a response
+    Pkt6Ptr adv = srv_->fake_sent_.front();
+    ASSERT_TRUE(adv);
+
+    // Get client-id...
+    OptionPtr clientid = adv->getOption(D6O_SERVERID);
+
+    // ... and check if it is the modified value
+    OptionPtr expected = createOption(D6O_SERVERID);
+    EXPECT_TRUE(clientid->equal(expected));
+}
+
+// Checks if callouts installed on pkt6_send is able to delete
+// existing options and that server applies those changes. In particular,
+// we are trying to send a packet without server-id. The packet should
+// be sent
+TEST_F(HooksDhcpv6SrvTest, deleteServerId_pkt6_send) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_send", pkt6_send_delete_serverid));
+
+    // Let's create a simple SOLICIT
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server indeed sent a malformed ADVERTISE
+    ASSERT_EQ(1, srv_->fake_sent_.size());
+
+    // Get that ADVERTISE
+    Pkt6Ptr adv = srv_->fake_sent_.front();
+    ASSERT_TRUE(adv);
+
+    // Make sure that it does not have server-id
+    EXPECT_FALSE(adv->getOption(D6O_SERVERID));
+}
+
+// Checks if callouts installed on pkt6_skip is able to set skip flag that
+// will cause the server to not process the packet (drop), even though it is valid.
+TEST_F(HooksDhcpv6SrvTest, skip_pkt6_send) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "pkt6_send", pkt6_send_skip));
+
+    // Let's create a simple REQUEST
+    Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
+
+    // Simulate that we have received that traffic
+    srv_->fakeReceive(sol);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive6(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered pkt6_receive callback.
+    srv_->run();
+
+    // Check that the server send the packet
+    ASSERT_EQ(1, srv_->fake_sent_.size());
+
+    // But the sent packet should have 0 length (we told the server to
+    // skip pack(), but did not do packing outselves)
+    Pkt6Ptr sent = srv_->fake_sent_.front();
+
+    // The actual size of sent packet should be 0
+    EXPECT_EQ(0, sent->getBuffer().getLength());
+}
+
+// This test checks if subnet6_select callout is triggered and reports
+// valid parameters
+TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "subnet6_select", subnet6_select_callout));
+
+    // Configure 2 subnets, both directly reachable over local interface
+    // (let's not complicate the matter with relays)
+    string config = "{ \"interfaces\": [ \"*\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/64\" ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"" + valid_iface_ + "\" "
+        " }, {"
+        "    \"pool\": [ \"2001:db8:2::/64\" ],"
+        "    \"subnet\": \"2001:db8:2::/48\" "
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ElementPtr json = Element::fromJSON(config);
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+    ASSERT_TRUE(status);
+    comment_ = parseAnswer(rcode_, status);
+    ASSERT_EQ(0, rcode_);
+
+    // Prepare solicit packet. Server should select first subnet for it
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface(valid_iface_);
+    sol->addOption(generateIA(234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr adv = srv_->processSolicit(sol);
+
+    // Check if we get response at all
+    ASSERT_TRUE(adv);
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("subnet6_select", callback_name_);
+
+    // Check that pkt6 argument passing was successful and returned proper value
+    EXPECT_TRUE(callback_pkt6_.get() == sol.get());
+
+    const Subnet6Collection* exp_subnets = CfgMgr::instance().getSubnets6();
+
+    // The server is supposed to pick the first subnet, because of matching
+    // interface. Check that the value is reported properly.
+    ASSERT_TRUE(callback_subnet6_);
+    EXPECT_EQ(callback_subnet6_.get(), exp_subnets->front().get());
+
+    // Server is supposed to report two subnets
+    ASSERT_EQ(exp_subnets->size(), callback_subnet6collection_->size());
+
+    // Compare that the available subnets are reported as expected
+    EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet6collection_)[0].get());
+    EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet6collection_)[1].get());
+}
+
+// This test checks if callout installed on subnet6_select hook point can pick
+// a different subnet.
+TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "subnet6_select", subnet6_select_different_subnet_callout));
+
+    // Configure 2 subnets, both directly reachable over local interface
+    // (let's not complicate the matter with relays)
+    string config = "{ \"interfaces\": [ \"*\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/64\" ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"" + valid_iface_ + "\" "
+        " }, {"
+        "    \"pool\": [ \"2001:db8:2::/64\" ],"
+        "    \"subnet\": \"2001:db8:2::/48\" "
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ElementPtr json = Element::fromJSON(config);
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
+    ASSERT_TRUE(status);
+    comment_ = parseAnswer(rcode_, status);
+    ASSERT_EQ(0, rcode_);
+
+    // Prepare solicit packet. Server should select first subnet for it
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+    sol->setRemoteAddr(IOAddress("fe80::abcd"));
+    sol->setIface(valid_iface_);
+    sol->addOption(generateIA(234, 1500, 3000));
+    OptionPtr clientid = generateClientId();
+    sol->addOption(clientid);
+
+    // Pass it to the server and get an advertise
+    Pkt6Ptr adv = srv_->processSolicit(sol);
+
+    // Check if we get response at all
+    ASSERT_TRUE(adv);
+
+    // The response should have an address from second pool, so let's check it
+    OptionPtr tmp = adv->getOption(D6O_IA_NA);
+    ASSERT_TRUE(tmp);
+    boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+    ASSERT_TRUE(ia);
+    tmp = ia->getOption(D6O_IAADDR);
+    ASSERT_TRUE(tmp);
+    boost::shared_ptr<Option6IAAddr> addr_opt =
+        boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
+    ASSERT_TRUE(addr_opt);
+
+    // Get all subnets and use second subnet for verification
+    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    ASSERT_EQ(2, subnets->size());
+
+    // Advertised address must belong to the second pool (in subnet's range,
+    // in dynamic pool)
+    EXPECT_TRUE((*subnets)[1]->inRange(addr_opt->getAddress()));
+    EXPECT_TRUE((*subnets)[1]->inPool(addr_opt->getAddress()));
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are triggered.
+TEST_F(HooksDhcpv6SrvTest, basic_lease6_renew) {
+    NakedDhcpv6Srv srv(0);
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_renew", lease6_renew_callout));
+
+    const IOAddress addr("2001:db8:1:1::cafe:babe");
+    const uint32_t iaid = 234;
+
+    // Generate client-id also duid_
+    OptionPtr clientid = generateClientId();
+
+    // Check that the address we are about to use is indeed in pool
+    ASSERT_TRUE(subnet_->inPool(addr));
+
+    // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+    // value on purpose. They should be updated during RENEW.
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
+                               501, 502, 503, 504, subnet_->getID(), 0));
+    lease->cltt_ = 1234;
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    // Check that the lease is really in the database
+    Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_TRUE(l);
+
+    // Check that T1, T2, preferred, valid and cltt really set and not using
+    // previous (500, 501, etc.) values
+    EXPECT_NE(l->t1_, subnet_->getT1());
+    EXPECT_NE(l->t2_, subnet_->getT2());
+    EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+    EXPECT_NE(l->valid_lft_, subnet_->getValid());
+    EXPECT_NE(l->cltt_, time(NULL));
+
+    // Let's create a RENEW
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
+
+    OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+    ia->addOption(renewed_addr_opt);
+    req->addOption(ia);
+    req->addOption(clientid);
+
+    // Server-id is mandatory in RENEW
+    req->addOption(srv.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv.processRenew(req);
+    ASSERT_TRUE(reply);
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("lease6_renew", callback_name_);
+
+    // Check that appropriate parameters are passed to the callouts
+    EXPECT_TRUE(callback_pkt6_);
+    EXPECT_TRUE(callback_lease6_);
+    EXPECT_TRUE(callback_ia_na_);
+
+    // Check if all expected parameters were really received
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back("query6");
+    expected_argument_names.push_back("lease6");
+    expected_argument_names.push_back("ia_na");
+
+    sort(callback_argument_names_.begin(), callback_argument_names_.end());
+    sort(expected_argument_names.begin(), expected_argument_names.end());
+
+    EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+    // Check if we get response at all
+    checkResponse(reply, DHCPV6_REPLY, 1234);
+
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
+    ASSERT_TRUE(tmp);
+
+    // Check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
+                                                           subnet_->getT2());
+
+    ASSERT_TRUE(addr_opt);
+    // Check that the lease is really in the database
+    l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
+    ASSERT_TRUE(l);
+
+    // Check that the lease has been returned
+    ASSERT_TRUE(callback_lease6_);
+
+    // Check that the returned lease6 in callout is the same as the one in the
+    // database
+    EXPECT_TRUE(*callback_lease6_ == *l);
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are able to change the lease being updated.
+TEST_F(HooksDhcpv6SrvTest, leaseUpdate_lease6_renew) {
+    NakedDhcpv6Srv srv(0);
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_renew", lease6_renew_update_callout));
+
+    const IOAddress addr("2001:db8:1:1::cafe:babe");
+    const uint32_t iaid = 234;
+
+    // Generate client-id also duid_
+    OptionPtr clientid = generateClientId();
+
+    // Check that the address we are about to use is indeed in pool
+    ASSERT_TRUE(subnet_->inPool(addr));
+
+    // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+    // value on purpose. They should be updated during RENEW.
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
+                               501, 502, 503, 504, subnet_->getID(), 0));
+    lease->cltt_ = 1234;
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    // Check that the lease is really in the database
+    Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_TRUE(l);
+
+    // Check that T1, T2, preferred, valid and cltt really set and not using
+    // previous (500, 501, etc.) values
+    EXPECT_NE(l->t1_, subnet_->getT1());
+    EXPECT_NE(l->t2_, subnet_->getT2());
+    EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+    EXPECT_NE(l->valid_lft_, subnet_->getValid());
+    EXPECT_NE(l->cltt_, time(NULL));
+
+    // Let's create a RENEW
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
+
+    OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+    ia->addOption(renewed_addr_opt);
+    req->addOption(ia);
+    req->addOption(clientid);
+
+    // Server-id is mandatory in RENEW
+    req->addOption(srv.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv.processRenew(req);
+    ASSERT_TRUE(reply);
+
+    // Check if we get response at all
+    checkResponse(reply, DHCPV6_REPLY, 1234);
+
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
+    ASSERT_TRUE(tmp);
+
+    // Check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 1000, 1001, 1002);
+
+    ASSERT_TRUE(addr_opt);
+    // Check that the lease is really in the database
+    l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
+    ASSERT_TRUE(l);
+
+    // Check that we chose the distinct override values
+    ASSERT_NE(override_t1_,        subnet_->getT1());
+    ASSERT_NE(override_t2_,        subnet_->getT2());
+    ASSERT_NE(override_preferred_, subnet_->getPreferred());
+    EXPECT_NE(override_valid_,     subnet_->getValid());
+
+    // Check that T1, T2, preferred, valid were overridden the the callout
+    EXPECT_EQ(override_t1_, l->t1_);
+    EXPECT_EQ(override_t2_, l->t2_);
+    EXPECT_EQ(override_preferred_, l->preferred_lft_);
+    EXPECT_EQ(override_valid_, l->valid_lft_);
+
+    // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
+    int32_t cltt = static_cast<int32_t>(l->cltt_);
+    int32_t expected = static_cast<int32_t>(time(NULL));
+    // Equality or difference by 1 between cltt and expected is ok.
+    EXPECT_GE(1, abs(cltt - expected));
+
+    EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are able to set the skip flag that will
+// reject the renewal
+TEST_F(HooksDhcpv6SrvTest, skip_lease6_renew) {
+    NakedDhcpv6Srv srv(0);
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_renew", lease6_renew_skip_callout));
+
+    const IOAddress addr("2001:db8:1:1::cafe:babe");
+    const uint32_t iaid = 234;
+
+    // Generate client-id also duid_
+    OptionPtr clientid = generateClientId();
+
+    // Check that the address we are about to use is indeed in pool
+    ASSERT_TRUE(subnet_->inPool(addr));
+
+    // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+    // value on purpose. They should be updated during RENEW.
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
+                               501, 502, 503, 504, subnet_->getID(), 0));
+    lease->cltt_ = 1234;
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    // Check that the lease is really in the database
+    Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_TRUE(l);
+
+    // Check that T1, T2, preferred, valid and cltt really set and not using
+    // previous (500, 501, etc.) values
+    EXPECT_NE(l->t1_, subnet_->getT1());
+    EXPECT_NE(l->t2_, subnet_->getT2());
+    EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+    EXPECT_NE(l->valid_lft_, subnet_->getValid());
+    EXPECT_NE(l->cltt_, time(NULL));
+
+    // Let's create a RENEW
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
+
+    OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+    ia->addOption(renewed_addr_opt);
+    req->addOption(ia);
+    req->addOption(clientid);
+
+    // Server-id is mandatory in RENEW
+    req->addOption(srv.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv.processRenew(req);
+    ASSERT_TRUE(reply);
+
+    // Check that our callback was called
+    EXPECT_EQ("lease6_renew", callback_name_);
+
+    l = LeaseMgrFactory::instance().getLease6(addr);
+
+    // Check that the old values are still there and they were not
+    // updated by the renewal
+    EXPECT_NE(l->t1_, subnet_->getT1());
+    EXPECT_NE(l->t2_, subnet_->getT2());
+    EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+    EXPECT_NE(l->valid_lft_, subnet_->getValid());
+    EXPECT_NE(l->cltt_, time(NULL));
+}
+
+// This test verifies that incoming (positive) RELEASE can be handled properly,
+// that a REPLY is generated, that the response has status code and that the
+// lease is indeed removed from the database.
+//
+// expected:
+// - returned REPLY message has copy of client-id
+// - returned REPLY message has server-id
+// - returned REPLY message has IA that does not include an IAADDR
+// - lease is actually removed from LeaseMgr
+TEST_F(HooksDhcpv6SrvTest, basic_lease6_release) {
+    NakedDhcpv6Srv srv(0);
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_release", lease6_release_callout));
+
+    const IOAddress addr("2001:db8:1:1::cafe:babe");
+    const uint32_t iaid = 234;
+
+    // Generate client-id also duid_
+    OptionPtr clientid = generateClientId();
+
+    // Check that the address we are about to use is indeed in pool
+    ASSERT_TRUE(subnet_->inPool(addr));
+
+    // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+    // value on purpose. They should be updated during RENEW.
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
+                               501, 502, 503, 504, subnet_->getID(), 0));
+    lease->cltt_ = 1234;
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    // Check that the lease is really in the database
+    Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_TRUE(l);
+
+    // Let's create a RELEASE
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
+
+    OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+    ia->addOption(released_addr_opt);
+    req->addOption(ia);
+    req->addOption(clientid);
+
+    // Server-id is mandatory in RELEASE
+    req->addOption(srv.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv.processRelease(req);
+
+    ASSERT_TRUE(reply);
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("lease6_release", callback_name_);
+
+    // Check that appropriate parameters are passed to the callouts
+    EXPECT_TRUE(callback_pkt6_);
+    EXPECT_TRUE(callback_lease6_);
+
+    // Check if all expected parameters were really received
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back("query6");
+    expected_argument_names.push_back("lease6");
+    sort(callback_argument_names_.begin(), callback_argument_names_.end());
+    sort(expected_argument_names.begin(), expected_argument_names.end());
+    EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+    // Check that the lease is really gone in the database
+    // get lease by address
+    l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_FALSE(l);
+
+    // Get lease by subnetid/duid/iaid combination
+    l = LeaseMgrFactory::instance().getLease6(*duid_, iaid, subnet_->getID());
+    ASSERT_FALSE(l);
+}
+
+// This test verifies that incoming (positive) RELEASE can be handled properly,
+// that a REPLY is generated, that the response has status code and that the
+// lease is indeed removed from the database.
+//
+// expected:
+// - returned REPLY message has copy of client-id
+// - returned REPLY message has server-id
+// - returned REPLY message has IA that does not include an IAADDR
+// - lease is actually removed from LeaseMgr
+TEST_F(HooksDhcpv6SrvTest, skip_lease6_release) {
+    NakedDhcpv6Srv srv(0);
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_release", lease6_release_skip_callout));
+
+    const IOAddress addr("2001:db8:1:1::cafe:babe");
+    const uint32_t iaid = 234;
+
+    // Generate client-id also duid_
+    OptionPtr clientid = generateClientId();
+
+    // Check that the address we are about to use is indeed in pool
+    ASSERT_TRUE(subnet_->inPool(addr));
+
+    // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+    // value on purpose. They should be updated during RENEW.
+    Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
+                               501, 502, 503, 504, subnet_->getID(), 0));
+    lease->cltt_ = 1234;
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    // Check that the lease is really in the database
+    Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_TRUE(l);
+
+    // Let's create a RELEASE
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
+
+    OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+    ia->addOption(released_addr_opt);
+    req->addOption(ia);
+    req->addOption(clientid);
+
+    // Server-id is mandatory in RELEASE
+    req->addOption(srv.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv.processRelease(req);
+
+    ASSERT_TRUE(reply);
+
+    // Check that the callback called is indeed the one we installed
+    EXPECT_EQ("lease6_release", callback_name_);
+
+    // Check that the lease is still there
+    // get lease by address
+    l = LeaseMgrFactory::instance().getLease6(addr);
+    ASSERT_TRUE(l);
+
+    // Get lease by subnetid/duid/iaid combination
+    l = LeaseMgrFactory::instance().getLease6(*duid_, iaid, subnet_->getID());
+    ASSERT_TRUE(l);
+}
+
+}   // end of anonymous namespace
diff --git a/src/lib/dhcp/pkt6.h b/src/lib/dhcp/pkt6.h
index 70836ae..a7f95c6 100644
--- a/src/lib/dhcp/pkt6.h
+++ b/src/lib/dhcp/pkt6.h
@@ -141,11 +141,6 @@ public:
     /// @return reference to output buffer
     const isc::util::OutputBuffer& getBuffer() const { return (bufferOut_); };
 
-    /// @brief Returns reference to input buffer.
-    ///
-    /// @return reference to input buffer
-    const OptionBuffer& getData() const { return(data_); }
-
     /// @brief Returns protocol of this packet (UDP or TCP).
     ///
     /// @return protocol type
@@ -349,9 +344,7 @@ public:
 
     /// collection of options present in this message
     ///
-    /// @todo: Text mentions protected, but this is really public
-    ///
-    /// @warning This protected member is accessed by derived
+    /// @warning This public member is accessed by derived
     /// classes directly. One of such derived classes is
     /// @ref perfdhcp::PerfPkt6. The impact on derived clasess'
     /// behavior must be taken into consideration before making
@@ -412,6 +405,18 @@ public:
     /// to be impossible). Therefore public field is considered the best
     /// (or least bad) solution.
     std::vector<RelayInfo> relay_info_;
+
+
+    /// unparsed data (in received packets)
+    ///
+    /// @warning This public member is accessed by derived
+    /// classes directly. One of such derived classes is
+    /// @ref perfdhcp::PerfPkt6. The impact on derived clasess'
+    /// behavior must be taken into consideration before making
+    /// changes to this member such as access scope restriction or
+    /// data format change etc.
+    OptionBuffer data_;
+
 protected:
     /// Builds on wire packet for TCP transmission.
     ///
@@ -494,16 +499,6 @@ protected:
     /// DHCPv6 transaction-id
     uint32_t transid_;
 
-    /// unparsed data (in received packets)
-    ///
-    /// @warning This protected member is accessed by derived
-    /// classes directly. One of such derived classes is
-    /// @ref perfdhcp::PerfPkt6. The impact on derived clasess'
-    /// behavior must be taken into consideration before making
-    /// changes to this member such as access scope restriction or
-    /// data format change etc.
-    OptionBuffer data_;
-
     /// name of the network interface the packet was received/to be sent over
     std::string iface_;
 
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index cdb0159..488ecb3 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -766,9 +766,9 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     ASSERT_TRUE(rcvPkt); // received our own packet
 
     // let's check that we received what was sent
-    ASSERT_EQ(sendPkt->getData().size(), rcvPkt->getData().size());
-    EXPECT_EQ(0, memcmp(&sendPkt->getData()[0], &rcvPkt->getData()[0],
-                        rcvPkt->getData().size()));
+    ASSERT_EQ(sendPkt->data_.size(), rcvPkt->data_.size());
+    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
+                        rcvPkt->data_.size()));
 
     EXPECT_EQ(sendPkt->getRemoteAddr().toText(), rcvPkt->getRemoteAddr().toText());
 
diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc
index a691010..138148a 100644
--- a/src/lib/dhcp/tests/pkt6_unittest.cc
+++ b/src/lib/dhcp/tests/pkt6_unittest.cc
@@ -64,8 +64,8 @@ TEST_F(Pkt6Test, constructor) {
     uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
     scoped_ptr<Pkt6> pkt1(new Pkt6(data, sizeof(data)));
 
-    EXPECT_EQ(6, pkt1->getData().size());
-    EXPECT_EQ(0, memcmp( &pkt1->getData()[0], data, sizeof(data)));
+    EXPECT_EQ(6, pkt1->data_.size());
+    EXPECT_EQ(0, memcmp( &pkt1->data_[0], data, sizeof(data)));
 }
 
 /// @brief returns captured actual SOLICIT packet
diff --git a/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc b/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc
index de134cc..02c009e 100644
--- a/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc
+++ b/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc
@@ -111,8 +111,8 @@ TEST_F(PerfPkt6Test, Constructor) {
     // Test constructor to be used for incoming messages.
     // Use default (1) offset value and don't specify transaction id.
     boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data)));
-    EXPECT_EQ(sizeof(data), pkt1->getData().size());
-    EXPECT_EQ(0, memcmp(&pkt1->getData()[0], data, sizeof(data)));
+    EXPECT_EQ(sizeof(data), pkt1->data_.size());
+    EXPECT_EQ(0, memcmp(&pkt1->data_[0], data, sizeof(data)));
     EXPECT_EQ(1, pkt1->getTransidOffset());
 
     // Test constructor to be used for outgoing messages.
@@ -121,8 +121,8 @@ TEST_F(PerfPkt6Test, Constructor) {
     const uint32_t transid = 0x010203;
     boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data),
                                                   offset_transid, transid));
-    EXPECT_EQ(sizeof(data), pkt2->getData().size());
-    EXPECT_EQ(0, memcmp(&pkt2->getData()[0], data, sizeof(data)));
+    EXPECT_EQ(sizeof(data), pkt2->data_.size());
+    EXPECT_EQ(0, memcmp(&pkt2->data_[0], data, sizeof(data)));
     EXPECT_EQ(0x010203, pkt2->getTransid());
     EXPECT_EQ(10, pkt2->getTransidOffset());
 }
@@ -163,7 +163,7 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
     // Get output buffer from packet 1 to create new packet
     // that will be later validated.
     util::OutputBuffer pkt1_output = pkt1->getBuffer();
-    ASSERT_EQ(pkt1_output.getLength(), pkt1->getData().size());
+    ASSERT_EQ(pkt1_output.getLength(), pkt1->data_.size());
     const uint8_t* pkt1_output_data = static_cast<const uint8_t*>
         (pkt1_output.getData());
     boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data,



More information about the bind10-changes mailing list