Browse Source

[master] Merge branch 'trac3246'

Conflicts:
	src/bin/dhcp6/tests/Makefile.am
Marcin Siodelski 11 years ago
parent
commit
50de7df419

+ 4 - 4
src/bin/dhcp6/dhcp6_srv.cc

@@ -1365,16 +1365,16 @@ Dhcpv6Srv::assignIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
     // Check if the client sent us a hint in his IA_PD. Clients may send an
     // address in their IA_NA options as a suggestion (e.g. the last address
     // they used before).
-    boost::shared_ptr<Option6IAPrefix> hintOpt =
+    boost::shared_ptr<Option6IAPrefix> hint_opt =
       boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(D6O_IAPREFIX));
     IOAddress hint("::");
-    if (hintOpt) {
-        hint = hintOpt->getAddress();
+    if (hint_opt) {
+        hint = hint_opt->getAddress();
     }
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_REQUEST)
         .arg(duid ? duid->toText() : "(no-duid)").arg(ia->getIAID())
-        .arg(hintOpt ? hint.toText() : "(no hint)");
+        .arg(hint_opt ? hint.toText() : "(no hint)");
 
     // "Fake" allocation is processing of SOLICIT message. We pretend to do an
     // allocation, but we do not put the lease in the database. That is ok,

+ 1 - 0
src/bin/dhcp6/tests/Makefile.am

@@ -85,6 +85,7 @@ dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc
 dhcp6_unittests_SOURCES += wireshark.cc
 dhcp6_unittests_SOURCES += dhcp6_client.cc dhcp6_client.h
 dhcp6_unittests_SOURCES += rebind_unittest.cc
+dhcp6_unittests_SOURCES += sarr_unittest.cc
 dhcp6_unittests_SOURCES += ../json_config_parser.cc ../json_config_parser.h
 dhcp6_unittests_SOURCES += config_parser_unittest.cc
 

+ 15 - 3
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -39,7 +39,8 @@ Dhcp6Client::Dhcp6Client() :
     srv_(boost::shared_ptr<NakedDhcpv6Srv>(new NakedDhcpv6Srv(0))),
     use_na_(false),
     use_pd_(false),
-    use_relay_(false) {
+    use_relay_(false),
+    prefix_hint_() {
 }
 
 Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
@@ -234,8 +235,11 @@ Dhcp6Client::doSolicit() {
                                                               1234)));
     }
     if (use_pd_) {
-        context_.query_->addOption(Option6IAPtr(new Option6IA(D6O_IA_PD,
-                                                              5678)));
+        Option6IAPtr ia(new Option6IA(D6O_IA_PD, 5678));
+        if (prefix_hint_) {
+            ia->addOption(prefix_hint_);
+        }
+        context_.query_->addOption(ia);
     }
     sendMsg(context_.query_);
     context_.response_ = receiveOneMsg();
@@ -358,6 +362,14 @@ Dhcp6Client::sendMsg(const Pkt6Ptr& msg) {
     srv_->run();
 }
 
+void
+Dhcp6Client::useHint(const uint32_t pref_lft, const uint32_t valid_lft,
+                     const uint8_t len, const std::string& prefix) {
+    prefix_hint_.reset(new Option6IAPrefix(D6O_IAPREFIX,
+                                           asiolink::IOAddress(prefix),
+                                           len, pref_lft, valid_lft));
+}
+
 
 } // end of namespace isc::dhcp::test
 } // end of namespace isc::dhcp

+ 24 - 1
src/bin/dhcp6/tests/dhcp6_client.h

@@ -26,7 +26,6 @@ namespace isc {
 namespace dhcp {
 namespace test {
 
-
 /// @brief DHCPv6 client used for unit testing.
 ///
 /// This class implements a DHCPv6 "client" which interoperates with the
@@ -76,6 +75,11 @@ public:
     /// Currently it simply contains the collection of leases acquired.
     struct Configuration {
         std::vector<LeaseInfo> leases_;
+
+        /// @brief Clears configuration.
+        void clear() {
+            leases_.clear();
+        }
     };
 
     /// @brief Holds the DHCPv6 messages taking part in transaction between
@@ -175,6 +179,13 @@ public:
     /// @todo Perform sanity checks on returned messages.
     void doRequest();
 
+    /// @brief Removes the stateful configuration obtained from the server.
+    ///
+    /// It removes all leases held by the client.
+    void clearConfig() {
+        config_.clear();
+    }
+
     /// @brief Simulates aging of leases by the specified number of seconds.
     ///
     /// This function moves back the time of acquired leases by the specified
@@ -250,6 +261,15 @@ public:
         dest_addr_ = dest_addr;
     }
 
+    /// @brief Sets a prefix hint to be sent to a server.
+    ///
+    /// @param pref_lft Preferred lifetime.
+    /// @param valid_lft Valid lifetime.
+    /// @param len Prefix length.
+    /// @param prefix Prefix for which the client has a preference.
+    void useHint(const uint32_t pref_lft, const uint32_t valid_lft,
+                 const uint8_t len, const std::string& prefix);
+
     /// @brief Place IA_NA options to request address assignment.
     ///
     /// This function configures the client to place IA_NA options in its
@@ -383,6 +403,9 @@ private:
     bool use_na_;    ///< Enable address assignment.
     bool use_pd_;    ///< Enable prefix delegation.
     bool use_relay_; ///< Enable relaying messages to the server.
+
+    /// @brief Pointer to the option holding a prefix hint.
+    Option6IAPrefixPtr prefix_hint_;
 };
 
 } // end of namespace isc::dhcp::test

+ 6 - 2
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -590,18 +590,22 @@ Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
 
 void
 Dhcpv6SrvTest::configure(const std::string& config) {
+    configure(config, srv_);
+}
+
+void
+Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
     ElementPtr json = data::Element::fromJSON(config);
     ConstElementPtr status;
 
     // Configure the server and make sure the config is accepted
-    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
     ASSERT_TRUE(status);
     int rcode;
     ConstElementPtr comment = config::parseAnswer(rcode, status);
     ASSERT_EQ(0, rcode);
 }
 
-
 // Generate IA_NA option with specified parameters
 boost::shared_ptr<Option6IA>
 NakedDhcpv6SrvTest::generateIA(uint16_t type, uint32_t iaid, uint32_t t1,

+ 7 - 2
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -354,8 +354,13 @@ public:
     /// @brief Runs DHCPv6 configuration from the JSON string.
     ///
     /// @param config String holding server configuration in JSON format.
-    void
-    configure(const std::string& config);
+    void configure(const std::string& config);
+
+    /// @brief Configure the DHCPv6 server using the JSON string.
+    ///
+    /// @param config String holding server configuration in JSON format.
+    /// @param srv Server to be configured.
+    void configure(const std::string& config, NakedDhcpv6Srv& srv);
 
     /// @brief Checks that server response (ADVERTISE or REPLY) contains proper
     ///        IA_NA option

+ 0 - 19
src/bin/dhcp6/tests/rebind_unittest.cc

@@ -208,12 +208,6 @@ public:
           iface_mgr_test_config_(true) {
     }
 
-    /// @brief Configure the DHCPv6 server using the JSON string.
-    ///
-    /// @param config New configuration in JSON format.
-    /// @param srv Server to be configured.
-    void configure(const std::string& config, NakedDhcpv6Srv& srv);
-
     /// @brief Make 4-way exchange to obtain a lease.
     ///
     /// @param config_index Index of the configuration held in @c REBIND_CONFIGS
@@ -230,19 +224,6 @@ public:
 };
 
 void
-RebindTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
-    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);
-    int rcode;
-    ConstElementPtr comment = config::parseAnswer(rcode, status);
-    ASSERT_EQ(0, rcode);
-}
-
-void
 RebindTest::requestLease(const int config_index, const int subnets_num,
                          Dhcp6Client& client) {
     // Check that the index is in the configuration table.

+ 124 - 0
src/bin/dhcp6/tests/sarr_unittest.cc

@@ -0,0 +1,124 @@
+// Copyright (C) 2014  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 <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <dhcp6/tests/dhcp6_client.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::test;
+
+namespace {
+
+/// @brief Set of JSON configurations used by the SARR unit tests.
+///
+/// - Configuration 0:
+///   - one subnet used on eth0 interface
+///   - prefixes of length 64, delegated from the pool: 2001:db8:3::/48
+const char* CONFIGS[] = {
+    // Configuration 0
+    "{ \"interfaces\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pd-pools\": ["
+        "        { \"prefix\": \"2001:db8:3::\", "
+        "          \"prefix-len\": 48, "
+        "          \"delegated-len\": 64"
+        "        } ],"
+        "    \"subnet\": \"2001:db8::/32\", "
+        "    \"interface-id\": \"\","
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 }"
+};
+
+/// @brief Test fixture class for testing 4-way exchange: Solicit-Advertise,
+/// Request-Reply.
+class SARRTest : public Dhcpv6SrvTest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Sets up fake interfaces.
+    SARRTest()
+        : Dhcpv6SrvTest(),
+          iface_mgr_test_config_(true) {
+    }
+
+    /// @brief Interface Manager's fake configuration control.
+    IfaceMgrTestConfig iface_mgr_test_config_;
+};
+
+/// Check that server processes correctly a prefix hint sent by the client.
+/// This test checks that the server doesn't allocate colliding prefixes
+/// as a result of receiving hints from two clients which set the
+/// non-significant bytes of the prefix in their hints. The server should zero
+/// the non-significant bytes of the hint and allocate the prefix of the
+/// correct (configured) length.
+TEST_F(SARRTest, directClientPrefixHint) {
+    Dhcp6Client client;
+    // Configure client to request IA_PD.
+    client.usePD();
+    configure(CONFIGS[0], *client.getServer());
+    // Make sure we ended-up having expected number of subnets configured.
+    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    ASSERT_EQ(1, subnets->size());
+    // Append IAPREFIX option to the client's message.
+    ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:3:33::33"));
+    // Perform 4-way exchange.
+    ASSERT_NO_THROW(client.doSARR());
+    // Server should have assigned a prefix.
+    ASSERT_EQ(1, client.getLeaseNum());
+    Lease6 lease_client = client.getLease(0);
+    // The server should correctly deal with the least significant bytes
+    // of the hint being set. It should set them to zero and use the
+    // valid portion of the hint.
+    EXPECT_EQ("2001:db8:3:33::", lease_client.addr_.toText());
+    // Server ignores other parts of the IAPREFIX option.
+    EXPECT_EQ(64, lease_client.prefixlen_);
+    EXPECT_EQ(3000, lease_client.preferred_lft_);
+    EXPECT_EQ(4000, lease_client.valid_lft_);
+    Lease6Ptr lease_server = checkLease(lease_client);
+    // Check that the server recorded the lease.
+    ASSERT_TRUE(lease_server);
+
+    // Remove existing lease and modify the DUID of the client to simulate
+    // the case that different client is trying to get the prefix.
+    client.clearConfig();
+    client.modifyDUID();
+
+    // Use the hint with some least significant bytes set.
+    ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:3:33::34"));
+    ASSERT_NO_THROW(client.doSARR());
+    // Server should assign a lease.
+    ASSERT_EQ(1, client.getLeaseNum());
+    lease_client = client.getLease(0);
+    // The hint collides with the existing lease, so the server should not
+    // assign for the second client.
+    EXPECT_NE("2001:db8:3:33::", lease_client.addr_.toText());
+    EXPECT_NE("2001:db8:3:33::34", lease_client.addr_.toText());
+    // Check that the assigned prefix belongs to the pool.
+    (*subnets)[0]->inPool(Lease::TYPE_PD, lease_client.addr_);
+    EXPECT_EQ(64, lease_client.prefixlen_);
+    EXPECT_EQ(3000, lease_client.preferred_lft_);
+    EXPECT_EQ(4000, lease_client.valid_lft_);
+    lease_server = checkLease(lease_client);
+    ASSERT_TRUE(lease_server);
+}
+
+} // end of anonymous namespace

+ 29 - 2
src/lib/dhcp/option6_iaprefix.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 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
@@ -86,7 +86,9 @@ void Option6IAPrefix::unpack(OptionBuffer::const_iterator begin,
     begin += sizeof(uint8_t);
 
     // 16 bytes: IPv6 address
-    addr_ = IOAddress::fromBytes(AF_INET6, &(*begin));
+    OptionBuffer address_with_mask;
+    mask(begin, begin + V6ADDRESS_LEN, prefix_len_, address_with_mask);
+    addr_ = IOAddress::fromBytes(AF_INET6, &(*address_with_mask.begin()));
     begin += V6ADDRESS_LEN;
 
     // unpack encapsulated options (the only defined so far is PD_EXCLUDE)
@@ -122,5 +124,30 @@ uint16_t Option6IAPrefix::len() {
     return (length);
 }
 
+void
+Option6IAPrefix::mask(OptionBuffer::const_iterator begin,
+                      OptionBuffer::const_iterator end,
+                      const uint8_t len,
+                      OptionBuffer& output_address) {
+    output_address.resize(16, 0);
+    if (len >= 128) {
+        std::copy(begin, end, output_address.begin());
+    } else if (len > 0) {
+        // All the bits that represent whole octets of the prefix are copied with
+        // no change.
+        std::copy(begin, begin + static_cast<uint8_t>(len/8), output_address.begin());
+        // The remaining significant bits of the last octet have to be left unchanged,
+        // but the remaining bits of this octet must be set to zero. The number of
+        // significant bits is calculated as a reminder from the devision of the
+        // prefix length by 8 (by size of the octet). The number of bits to be set
+        // to zero is therefore calculated as: 8 - (len % 8).
+        // Next, the mask is created by shifting the 0xFF by the number of bits
+        // to be set to 0. By performing logical AND of this mask with the original
+        // value of the last octet we get the final value for the new octet.
+        output_address[len/8] = (*(begin + len/8) & (0xFF << (8 - (len % 8))));
+    }
+}
+
+
 } // end of namespace isc::dhcp
 } // end of namespace isc

+ 42 - 3
src/lib/dhcp/option6_iaprefix.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 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
@@ -33,9 +33,29 @@ namespace dhcp {
 /// a prefix length) 2 methods are used: getAddress() and getLength(). Although
 /// using getAddress() to obtain base prefix is somewhat counter-intuitive at
 /// first, it becomes obvious when one realizes that an address is a special
-/// case of a prefix with /128. It makes everyone's like much easier, because
+/// case of a prefix with /128. It makes everyone's life much easier, because
 /// the base prefix doubles as a regular address in many cases, e.g. when
 /// searching for a lease.
+///
+/// When searching for a prefix in the database or simply comparing two prefixes
+/// for equality, it is important that only the significant parts of the
+/// prefixes are compared. It is possible that the client or a server sends a
+/// prefix which has non-significant bits (beyond prefix length) set. The
+/// server or client receiving such a prefix should be liberal and not discard
+/// this prefix. It should rather ignore the non-significant bits. Therefore
+/// the unpack() function, which parses the prefix from the wire, always sets
+/// the non-significant bits to 0 so as two prefixes received on the wire can
+/// be compared without additional processing.
+///
+/// @todo Currently, the constructor which creates the option from the textual
+/// format doesn't set non-significant bits to 0. This is because it is assumed
+/// that the prefixes from the string are created locally (not received over the
+/// wire) and should be validated before the option is created. If we wanted
+/// to set non-significant bits to 0 when the prefix is created from the textual
+/// format it would have some peformance implications, because the option would
+/// need to be turned into wire format, appropriate bits set to 0 and then
+/// option would need to be created again from the wire format. We may consider
+/// doing it if we find a use case where it is required.
 class Option6IAPrefix : public Option6IAAddr {
 
 public:
@@ -74,6 +94,11 @@ public:
 
     /// @brief Parses received buffer.
     ///
+    /// This function calls the @c Option6IAPrefix::mask function to set the
+    /// non-significant bits of the prefix (bits beyond the length of the
+    /// prefix) to zero. See the @c Option6IAPrefix class documentation for
+    /// details why it is done.
+    ///
     /// @throw OutOfRange when buffer is shorter than 25 bytes
     ///
     /// @param begin iterator to first byte of option data
@@ -100,7 +125,21 @@ public:
     /// returns data length (data length + DHCPv4/DHCPv6 option header)
     virtual uint16_t len();
 
-protected:
+private:
+
+    /// @brief Apply mask of the specific length to the IPv6 address.
+    ///
+    /// @param begin Iterator pointing to the buffer holding IPv6 address.
+    /// @param end Iterator pointing to the end of the buffer holding IPv6
+    /// address.
+    /// @param len Length of the mask to be applied.
+    /// @param [out] output_address Reference to the buffer where the address
+    /// with a mask applied is output.
+    void mask(OptionBuffer::const_iterator begin,
+              OptionBuffer::const_iterator end,
+              const uint8_t len,
+              OptionBuffer& output_address);
+
     uint8_t prefix_len_;
 };
 

+ 89 - 19
src/lib/dhcp/tests/option6_iaprefix_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2014 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
@@ -36,7 +36,7 @@ using namespace isc::asiolink;
 namespace {
 class Option6IAPrefixTest : public ::testing::Test {
 public:
-    Option6IAPrefixTest() : buf_(255), outBuf_(255) {
+    Option6IAPrefixTest() : buf_(255), out_buf_(255) {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 255 - i;
         }
@@ -45,7 +45,7 @@ public:
     /// @brief creates on-wire representation of IAPREFIX option
     ///
     /// buf_ field is set up to have IAPREFIX with preferred=1000,
-    /// valid=3000000000 and prefix beign 2001:db8:1::dead:beef/77
+    /// valid=3000000000 and prefix being 2001:db8:1:0:afaf:0:dead:beef/77
     void setExampleBuffer() {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 0;
@@ -69,10 +69,12 @@ public:
         buf_[12] = 0xb8;
         buf_[13] = 0x00;
         buf_[14] = 0x01;
+        buf_[17] = 0xaf;
+        buf_[18] = 0xaf;
         buf_[21] = 0xde;
         buf_[22] = 0xad;
         buf_[23] = 0xbe;
-        buf_[24] = 0xef; // 2001:db8:1::dead:beef
+        buf_[24] = 0xef; // 2001:db8:1:0:afaf:0:dead:beef
     }
 
 
@@ -82,15 +84,22 @@ public:
     ///
     /// @param opt IAPREFIX option being tested
     /// @param expected_type expected option type
-    void checkOption(Option6IAPrefix& opt, uint16_t expected_type) {
+    /// @param expected_length Expected length of the prefix.
+    /// @param expected_address Expected prefix value in the textual format.
+    void checkOption(Option6IAPrefix& opt, const uint16_t expected_type,
+                     const uint8_t expected_length,
+                     const std::string& expected_address) {
 
         // Check if all fields have expected values
         EXPECT_EQ(Option::V6, opt.getUniverse());
         EXPECT_EQ(expected_type, opt.getType());
-        EXPECT_EQ("2001:db8:1::dead:beef", opt.getAddress().toText());
+        EXPECT_EQ(expected_address, opt.getAddress().toText());
         EXPECT_EQ(1000, opt.getPreferred());
         EXPECT_EQ(3000000000U, opt.getValid());
-        EXPECT_EQ(77, opt.getLength());
+        // uint8_t is often represented as a character type (char). Convert it
+        // to integer so as it is logged as a numeric value instead.
+        EXPECT_EQ(static_cast<int>(expected_length),
+                  static_cast<int>(opt.getLength()));
 
         // 4 bytes header + 25 bytes content
         EXPECT_EQ(Option::OPTION6_HDR_LEN + Option6IAPrefix::OPTION6_IAPREFIX_LEN,
@@ -105,7 +114,7 @@ public:
     /// @param expected_type expected option type
     void checkOutputBuffer(uint16_t expected_type) {
         // Check if pack worked properly:
-        const uint8_t* out = (const uint8_t*)outBuf_.getData();
+        const uint8_t* out = static_cast<const uint8_t*>(out_buf_.getData());
 
         // - if option type is correct
         EXPECT_EQ(expected_type, out[0]*256 + out[1]);
@@ -118,11 +127,12 @@ public:
     }
 
     OptionBuffer buf_;
-    OutputBuffer outBuf_;
+    OutputBuffer out_buf_;
 };
 
-// Tests if receiving option can be parsed correctly
-TEST_F(Option6IAPrefixTest, basic) {
+// Tests if a received option is parsed correctly. For the prefix length between
+// 0 and 128 the non-significant bits should be set to 0.
+TEST_F(Option6IAPrefixTest, parseShort) {
 
     setExampleBuffer();
 
@@ -133,17 +143,75 @@ TEST_F(Option6IAPrefixTest, basic) {
     ASSERT_TRUE(opt);
 
     // Pack this option
-    opt->pack(outBuf_);
-    EXPECT_EQ(29, outBuf_.getLength());
+    opt->pack(out_buf_);
+    EXPECT_EQ(29, out_buf_.getLength());
 
-    checkOption(*opt, D6O_IAPREFIX);
+    // The non-significant bits (above 77) of the received prefix should be
+    // set to zero.
+    checkOption(*opt, D6O_IAPREFIX, 77, "2001:db8:1:0:afa8::");
 
+    // Set non-significant bits in the reference buffer to 0, so as the buffer
+    // can be directly compared with the option buffer.
+    buf_[18] = 0xa8;
+    buf_.insert(buf_.begin() + 19, 5, 0);
     checkOutputBuffer(D6O_IAPREFIX);
 
     // Check that option can be disposed safely
     EXPECT_NO_THROW(opt.reset());
 }
 
+// Tests if a received option holding prefix of 128 bits is parsed correctly. 
+TEST_F(Option6IAPrefixTest, parseLong) {
+
+    setExampleBuffer();
+    // Set prefix length to the maximal value.
+    buf_[8] = 128;
+
+    // Create an option (unpack content)
+    boost::scoped_ptr<Option6IAPrefix> opt;
+    ASSERT_NO_THROW(opt.reset(new Option6IAPrefix(D6O_IAPREFIX, buf_.begin(),
+                                                  buf_.begin() + 25)));
+    ASSERT_TRUE(opt);
+
+    // Pack this option
+    opt->pack(out_buf_);
+    EXPECT_EQ(29, out_buf_.getLength());
+
+    checkOption(*opt, D6O_IAPREFIX, 128, "2001:db8:1:0:afaf:0:dead:beef");
+
+    checkOutputBuffer(D6O_IAPREFIX);
+
+    // Check that option can be disposed safely
+    EXPECT_NO_THROW(opt.reset());
+}
+
+// Check that the prefix having length of zero is represented as a "::".
+TEST_F(Option6IAPrefixTest, parseZero) {
+    setExampleBuffer();
+    // Set prefix length to 0.
+    buf_[8] = 0;
+
+    // Create an option (unpack content)
+    boost::scoped_ptr<Option6IAPrefix> opt;
+    ASSERT_NO_THROW(opt.reset(new Option6IAPrefix(D6O_IAPREFIX, buf_.begin(),
+                                                  buf_.begin() + 25)));
+    ASSERT_TRUE(opt);
+
+    // Pack this option
+    opt->pack(out_buf_);
+    EXPECT_EQ(29, out_buf_.getLength());
+
+    checkOption(*opt, D6O_IAPREFIX, 0, "::");
+
+    // Fill the address in the reference buffer with zeros.
+    buf_.insert(buf_.begin() + 9, 16, 0);
+    checkOutputBuffer(D6O_IAPREFIX);
+
+    // Check that option can be disposed safely
+    EXPECT_NO_THROW(opt.reset());
+}
+
+
 // Checks whether a new option can be built correctly
 TEST_F(Option6IAPrefixTest, build) {
 
@@ -151,14 +219,15 @@ TEST_F(Option6IAPrefixTest, build) {
     setExampleBuffer();
 
     ASSERT_NO_THROW(opt.reset(new Option6IAPrefix(12345,
-                    IOAddress("2001:db8:1::dead:beef"), 77, 1000, 3000000000u)));
+                    IOAddress("2001:db8:1:0:afaf:0:dead:beef"), 77,
+                                                  1000, 3000000000u)));
     ASSERT_TRUE(opt);
 
-    checkOption(*opt, 12345);
+    checkOption(*opt, 12345, 77, "2001:db8:1:0:afaf:0:dead:beef");
 
     // Check if we can build it properly
-    EXPECT_NO_THROW(opt->pack(outBuf_));
-    EXPECT_EQ(29, outBuf_.getLength());
+    EXPECT_NO_THROW(opt->pack(out_buf_));
+    EXPECT_EQ(29, out_buf_.getLength());
     checkOutputBuffer(12345);
 
     // Check that option can be disposed safely
@@ -181,7 +250,8 @@ TEST_F(Option6IAPrefixTest, negative) {
                  BadValue);
 
     // Prefix length can't be larger than 128
-    EXPECT_THROW(Option6IAPrefix(12345, IOAddress("192.0.2.1"), 255, 1000, 2000),
+    EXPECT_THROW(Option6IAPrefix(12345, IOAddress("192.0.2.1"),
+                                 255, 1000, 2000),
                  BadValue);
 }