Browse Source

[3145] Option6 IAPREFIX + unit-tests implemented

Tomek Mrugalski 11 years ago
parent
commit
066f45d1dd

+ 1 - 0
src/lib/dhcp/Makefile.am

@@ -26,6 +26,7 @@ libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
 libb10_dhcp___la_SOURCES += option4_client_fqdn.cc option4_client_fqdn.h
 libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
 libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
+libb10_dhcp___la_SOURCES += option6_iaprefix.cc option6_iaprefix.h
 libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
 libb10_dhcp___la_SOURCES += option6_client_fqdn.cc option6_client_fqdn.h
 libb10_dhcp___la_SOURCES += option_int.h

+ 120 - 0
src/lib/dhcp/option6_iaprefix.cc

@@ -0,0 +1,120 @@
+// 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 <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_iaprefix.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
+#include <sstream>
+
+#include <stdint.h>
+#include <arpa/inet.h>
+
+using namespace std;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+Option6IAPrefix::Option6IAPrefix(uint16_t type, const isc::asiolink::IOAddress& prefix,
+                                 uint8_t prefix_len, uint32_t pref, uint32_t valid)
+    :Option6IAAddr(type, prefix, pref, valid), prefix_len_(prefix_len) {
+}
+
+Option6IAPrefix::Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator begin,
+                             OptionBuffer::const_iterator end)
+    :Option6IAAddr(type, begin, end) {
+    unpack(begin, end);
+}
+
+void Option6IAPrefix::pack(isc::util::OutputBuffer& buf) {
+    if (!addr_.isV6()) {
+        isc_throw(isc::BadValue, addr_.toText()
+                  << " is not an IPv6 address");
+    }
+
+    buf.writeUint16(type_);
+
+    // len() returns complete option length. len field contains
+    // length without 4-byte option header
+    buf.writeUint16(len() - getHeaderLen());
+
+    buf.writeUint32(preferred_);
+    buf.writeUint32(valid_);
+    buf.writeUint8(prefix_len_);
+
+    buf.writeData(&addr_.toBytes()[0], isc::asiolink::V6ADDRESS_LEN);
+
+    // store encapsulated options (the only defined so far is PD_EXCLUDE)
+    packOptions(buf);
+}
+
+void Option6IAPrefix::unpack(OptionBuffer::const_iterator begin,
+                      OptionBuffer::const_iterator end) {
+    if ( distance(begin, end) < OPTION6_IAPREFIX_LEN) {
+        isc_throw(OutOfRange, "Option " << type_ << " truncated");
+    }
+
+    preferred_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+
+    valid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+
+    prefix_len_ = *begin;
+    begin += sizeof(uint8_t);
+
+    // 16 bytes: IPv6 address
+    addr_ = IOAddress::fromBytes(AF_INET6, &(*begin));
+    begin += V6ADDRESS_LEN;
+
+    // unpack encapsulated options (the only defined so far is PD_EXCLUDE)
+    unpackOptions(OptionBuffer(begin, end));
+}
+
+std::string Option6IAPrefix::toText(int indent /* =0 */) {
+    stringstream tmp;
+    for (int i=0; i<indent; i++)
+        tmp << " ";
+
+    tmp << "type=" << type_ << "(IAPREFIX) prefix=" << addr_.toText() << "/"
+        << prefix_len_ << ", preferred-lft=" << preferred_ << ", valid-lft="
+        << valid_ << endl;
+
+    for (OptionCollection::const_iterator opt=options_.begin();
+         opt!=options_.end();
+         ++opt) {
+        tmp << (*opt).second->toText(indent+2);
+    }
+    return tmp.str();
+}
+
+uint16_t Option6IAPrefix::len() {
+
+    uint16_t length = OPTION6_HDR_LEN + OPTION6_IAPREFIX_LEN;
+
+    // length of all suboptions
+    for (Option::OptionCollection::iterator it = options_.begin();
+         it != options_.end(); ++it) {
+        length += (*it).second->len();
+    }
+    return (length);
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc

+ 104 - 0
src/lib/dhcp/option6_iaprefix.h

@@ -0,0 +1,104 @@
+// 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.
+
+#ifndef OPTION6_IAPREFIX_H
+#define OPTION6_IAPREFIX_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option.h>
+
+namespace isc {
+namespace dhcp {
+
+
+/// @brief Class that represents IAPREFIX option in DHCPv6
+///
+/// It is based on a similar class that handles addresses.
+/// The major differences are fields order and prefix has also
+/// additional prefix length field.
+///
+/// It should be noted that to get a full prefix (2 values: base address, and
+/// a prefix length) 2 methods are used: getAddress() and getLength(). Although
+/// using getAddress() to obtain base address 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 make everyone's like much easier, because
+/// the base address doubles as a regular address in many cases, e.g. when
+/// searching for a lease.
+class Option6IAPrefix : public Option6IAAddr {
+
+public:
+    /// length of the fixed part of the IAPREFIX option
+    static const size_t OPTION6_IAPREFIX_LEN = 25;
+
+    /// @brief Ctor, used for options constructed (during transmission).
+    ///
+    /// @param type option type
+    /// @param addr reference to an address
+    /// @param prefix_length length (1-128)
+    /// @param preferred address preferred lifetime (in seconds)
+    /// @param valid address valid lifetime (in seconds)
+    Option6IAPrefix(uint16_t type, const isc::asiolink::IOAddress& addr,
+                    uint8_t prefix_length, uint32_t preferred, uint32_t valid);
+
+    /// @brief ctor, used for received options.
+    ///
+    /// @param type option type
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator begin,
+                    OptionBuffer::const_iterator end);
+
+    /// @brief Writes option in wire-format.
+    ///
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param buf pointer to a buffer
+    void pack(isc::util::OutputBuffer& buf);
+
+    /// @brief Parses received buffer.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin,
+                        OptionBufferConstIter end);
+
+    /// Returns string representation of the option.
+    ///
+    /// @param indent number of spaces before printing text
+    ///
+    /// @return string with text representation.
+    virtual std::string
+    toText(int indent = 0);
+
+    /// sets address in this option.
+    ///
+    /// @param addr address to be sent in this option
+    void setPrefix(const isc::asiolink::IOAddress& prefix,
+                   uint8_t length) { addr_ = prefix; prefix_len_ = length; }
+
+    uint8_t getLength() const { return prefix_len_; }
+
+    /// returns data length (data length + DHCPv4/DHCPv6 option header)
+    virtual uint16_t len();
+
+protected:
+    uint8_t prefix_len_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif // OPTION_IA_H

+ 1 - 0
src/lib/dhcp/tests/Makefile.am

@@ -36,6 +36,7 @@ libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
 libdhcp___unittests_SOURCES += option6_client_fqdn_unittest.cc
 libdhcp___unittests_SOURCES += option6_ia_unittest.cc
 libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
+libdhcp___unittests_SOURCES += option6_iaprefix_unittest.cc
 libdhcp___unittests_SOURCES += option_int_unittest.cc
 libdhcp___unittests_SOURCES += option_int_array_unittest.cc
 libdhcp___unittests_SOURCES += option_data_types_unittest.cc

+ 113 - 0
src/lib/dhcp/tests/option6_iaprefix_unittest.cc

@@ -0,0 +1,113 @@
+// Copyright (C) 2011-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 <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_iaprefix.h>
+#include <util/buffer.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+namespace {
+class Option6IAPrefixTest : public ::testing::Test {
+public:
+    Option6IAPrefixTest() : buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
+    }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
+};
+
+TEST_F(Option6IAPrefixTest, basic) {
+    for (int i = 0; i < 255; i++) {
+        buf_[i] = 0;
+    }
+
+    buf_[ 0] = 0x00;
+    buf_[ 1] = 0x00;
+    buf_[ 2] = 0x03;
+    buf_[ 3] = 0xe8; // preferred lifetime = 1000
+
+    buf_[ 4]  = 0xb2;
+    buf_[ 5] = 0xd0;
+    buf_[ 6] = 0x5e;
+    buf_[ 7] = 0x00; // valid lifetime = 3,000,000,000
+
+    buf_[ 8] = 77; // Prefix length = 77
+
+    buf_[ 9] = 0x20;
+    buf_[10] = 0x01;
+    buf_[11] = 0x0d;
+    buf_[12] = 0xb8;
+    buf_[13] = 0x00;
+    buf_[14] = 0x01;
+    buf_[21] = 0xde;
+    buf_[22] = 0xad;
+    buf_[23] = 0xbe;
+    buf_[24] = 0xef; // 2001:db8:1::dead:beef
+
+    // Create an option (unpack content)
+    boost::scoped_ptr<Option6IAPrefix> opt(new Option6IAPrefix(D6O_IAPREFIX,
+                                                           buf_.begin(),
+                                                           buf_.begin() + 25));
+
+    // Pack this option
+    opt->pack(outBuf_);
+
+    EXPECT_EQ(29, outBuf_.getLength());
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+
+    // 4 bytes header + 4 bytes content
+    EXPECT_EQ("2001:db8:1::dead:beef", opt->getAddress().toText());
+    EXPECT_EQ(1000, opt->getPreferred());
+    EXPECT_EQ(3000000000U, opt->getValid());
+    EXPECT_EQ(77, opt->getLength());
+
+    EXPECT_EQ(D6O_IAPREFIX, opt->getType());
+
+    EXPECT_EQ(Option::OPTION6_HDR_LEN + Option6IAPrefix::OPTION6_IAPREFIX_LEN,
+              opt->len());
+
+    // Check if pack worked properly:
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+
+    // - if option type is correct
+    EXPECT_EQ(D6O_IAPREFIX, out[0]*256 + out[1]);
+
+    // - if option length is correct
+    EXPECT_EQ(25, out[2]*256 + out[3]);
+
+    // - if option content is correct
+    EXPECT_EQ(0, memcmp(out + 4, &buf_[0], 25));
+
+    EXPECT_NO_THROW(opt.reset());
+}
+
+}