BIND 10 master, updated. 5765f9d6485ed12a16a65f89639d0d88bc2c3692 [master] Merge branch 'trac2304'

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Oct 23 09:11:32 UTC 2012


The branch, master has been updated
       via  5765f9d6485ed12a16a65f89639d0d88bc2c3692 (commit)
       via  9a52c2a5a52c35056f650594216366cac5560af1 (commit)
       via  c974d3a5e481c63242f128f630b9e7e5ac4f1359 (commit)
       via  b617d1a26e4e4fd536b37848b1dd39ff40f5213b (commit)
       via  9062cbabaeebead0b95bde1559d107fc35eeda1d (commit)
       via  f3414d4ba60432e36785c23ca55c633ad35298ab (commit)
       via  07b793c8f104dbb9116e3f94af7098498509288a (commit)
       via  85627bca2677b4e68d67c8ecd35fbfe409eda251 (commit)
       via  cd86c2c845e03de172d832256ea3542203f40a5f (commit)
       via  f4f708e4e93579989bf716d5851311a2b5aff6b5 (commit)
       via  71e12e0bc1d27327a0f3f520ae80041af38ce657 (commit)
       via  31c8d5e0b4cdec573baf77f09fca75a362f641b6 (commit)
       via  273e195ef434e87ebf9838381d4b49e8a3081acb (commit)
       via  b2d0a03b1efe54b85736d22932f311fd376473ba (commit)
       via  3c35688d9945077bceba65131bf0f9954181c7f4 (commit)
      from  a9688bc111e1cf1b62cfad222c2dab1351c81a4e (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 5765f9d6485ed12a16a65f89639d0d88bc2c3692
Merge: a9688bc 9a52c2a
Author: Marcin Siodelski <marcin at isc.org>
Date:   Tue Oct 23 10:35:14 2012 +0200

    [master] Merge branch 'trac2304'

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

Summary of changes:
 src/lib/dhcp/Makefile.am                         |    4 +
 src/lib/dhcp/option4_addrlst.h                   |    1 +
 src/lib/dhcp/option6_int.h                       |  189 +++++++
 src/lib/dhcp/option6_int_array.h                 |  228 ++++++++
 src/lib/dhcp/option_data_types.h                 |   89 ++++
 src/lib/dhcp/option_definition.cc                |  252 +++++++++
 src/lib/dhcp/option_definition.h                 |  383 ++++++++++++++
 src/lib/dhcp/tests/Makefile.am                   |    3 +
 src/lib/dhcp/tests/option6_int_array_unittest.cc |  420 +++++++++++++++
 src/lib/dhcp/tests/option6_int_unittest.cc       |  410 +++++++++++++++
 src/lib/dhcp/tests/option_definition_unittest.cc |  609 ++++++++++++++++++++++
 11 files changed, 2588 insertions(+)
 create mode 100644 src/lib/dhcp/option6_int.h
 create mode 100644 src/lib/dhcp/option6_int_array.h
 create mode 100644 src/lib/dhcp/option_data_types.h
 create mode 100644 src/lib/dhcp/option_definition.cc
 create mode 100644 src/lib/dhcp/option_definition.h
 create mode 100644 src/lib/dhcp/tests/option6_int_array_unittest.cc
 create mode 100644 src/lib/dhcp/tests/option6_int_unittest.cc
 create mode 100644 src/lib/dhcp/tests/option_definition_unittest.cc

-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 6585a38..140bb00 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -22,10 +22,14 @@ libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
 libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
 libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
 libb10_dhcp___la_SOURCES += option.cc option.h
+libb10_dhcp___la_SOURCES += option_data_types.h
+libb10_dhcp___la_SOURCES += option_definition.cc option_definition.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_addrlst.cc option6_addrlst.h
 libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
+libb10_dhcp___la_SOURCES += option6_int.h
+libb10_dhcp___la_SOURCES += option6_int_array.h
 libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
 libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
 libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
diff --git a/src/lib/dhcp/option4_addrlst.h b/src/lib/dhcp/option4_addrlst.h
index 3bedc6d..01a8a4b 100644
--- a/src/lib/dhcp/option4_addrlst.h
+++ b/src/lib/dhcp/option4_addrlst.h
@@ -20,6 +20,7 @@
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_array.hpp>
+#include <asiolink/io_address.h>
 #include <util/buffer.h>
 #include <dhcp/option.h>
 
diff --git a/src/lib/dhcp/option6_int.h b/src/lib/dhcp/option6_int.h
new file mode 100644
index 0000000..5fd5c19
--- /dev/null
+++ b/src/lib/dhcp/option6_int.h
@@ -0,0 +1,189 @@
+// Copyright (C) 2012 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_INT_H_
+#define OPTION6_INT_H_
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
+#include <util/io_utilities.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCPv6 option with single value.
+/// This value is of integer type and can be any of the following:
+/// - uint8_t,
+/// - uint16_t,
+/// - uint32_t,
+/// - int8_t,
+/// - int16_t,
+/// - int32_t.
+///
+/// @param T data field type (see above).
+template<typename T>
+class Option6Int: public Option {
+
+public:
+    /// @brief Constructor.
+    ///
+    /// @param type option type.
+    /// @param value option value.
+    ///
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6Int(uint16_t type, T value)
+        : Option(Option::V6, type), value_(value) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+    }
+
+    /// @brief Constructor.
+    ///
+    /// This constructor creates option from a buffer. This construtor
+    /// may throw exception if \ref unpack function throws during buffer
+    /// parsing.
+    ///
+    /// @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).
+    ///
+    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6Int(uint16_t type, OptionBufferConstIter begin,
+               OptionBufferConstIter end)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        unpack(begin, end);
+    }
+
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf buffer (option will be stored here)
+    ///
+    /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    void pack(isc::util::OutputBuffer& buf) {
+        buf.writeUint16(type_);
+        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        // Depending on the data type length we use different utility functions
+        // writeUint16 or writeUint32 which write the data in the network byte
+        // order to the provided buffer. The same functions can be safely used
+        // for either unsiged or signed integers so there is not need to create
+        // special cases for intX_t types.
+        switch (OptionDataTypes<T>::len) {
+        case 1:
+            buf.writeUint8(value_);
+            break;
+        case 2:
+            buf.writeUint16(value_);
+            break;
+        case 4:
+            buf.writeUint32(value_);
+            break;
+        default:
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        LibDHCP::packOptions6(buf, options_);
+    }
+
+    /// @brief Parses received buffer
+    ///
+    /// Parses received buffer and returns offset to the first unused byte after
+    /// parsed option.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    ///
+    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
+    /// @throw isc::dhcp::InvalidDataType if size of a data field type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+        if (distance(begin, end) < sizeof(T)) {
+            isc_throw(OutOfRange, "Option " << getType() << " truncated");
+        }
+        // @todo consider what to do if buffer is longer than data type.
+
+        // Depending on the data type length we use different utility functions
+        // readUint16 or readUint32 which read the data laid in the network byte
+        // order from the provided buffer. The same functions can be safely used
+        // for either unsiged or signed integers so there is not need to create
+        // special cases for intX_t types.
+        int data_size_len = OptionDataTypes<T>::len;
+        switch (data_size_len) {
+        case 1:
+            value_ = *begin;
+            break;
+        case 2:
+            value_ = isc::util::readUint16(&(*begin));
+            break;
+        case 4:
+            value_ = isc::util::readUint32(&(*begin));
+            break;
+        default:
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        // Use local variable to set a new value for this iterator.
+        // When using OptionDataTypes<T>::len directly some versions
+        // of clang complain about unresolved reference to
+        // OptionDataTypes structure during linking.
+        begin += data_size_len;
+        LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
+    }
+
+    /// @brief Set option value.
+    ///
+    /// @param value new option value.
+    void setValue(T value) { value_ = value; }
+
+    /// @brief Return option value.
+    ///
+    /// @return option value.
+    T getValue() const { return value_; }
+
+    /// @brief returns complete length of option
+    ///
+    /// Returns length of this option, including option header and suboptions
+    ///
+    /// @return length of this option
+    virtual uint16_t len() {
+        uint16_t length = OPTION6_HDR_LEN + sizeof(T);
+        // length of all suboptions
+        for (Option::OptionCollection::iterator it = options_.begin();
+             it != options_.end();
+             ++it) {
+            length += (*it).second->len();
+        }
+        return (length);
+    }
+
+private:
+
+    T value_;  ///< Value conveyed by the option.
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION6_INT_H_ */
diff --git a/src/lib/dhcp/option6_int_array.h b/src/lib/dhcp/option6_int_array.h
new file mode 100644
index 0000000..57aad1e
--- /dev/null
+++ b/src/lib/dhcp/option6_int_array.h
@@ -0,0 +1,228 @@
+// Copyright (C) 2012 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_INT_ARRAY_H_
+#define OPTION6_INT_ARRAY_H_
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
+#include <util/io_utilities.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCPv6 option with array of
+/// integer values. The type of the elements in the array can be
+/// any of the following:
+/// - uint8_t,
+/// - uint16_t,
+/// - uint32_t,
+/// - int8_t,
+/// - int16_t,
+/// - int32_t.
+///
+/// @warning Since this option may convey variable number of integer
+/// values, sub-options are should not be added in this option as
+/// there is no way to distinguish them from other data. The API will
+/// allow addition of sub-options but they will be ignored during
+/// packing and unpacking option data.
+///
+/// @param T data field type (see above).
+template<typename T>
+class Option6IntArray: public Option {
+
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Creates option with empty values vector.
+    ///
+    /// @param type option type.
+    ///
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6IntArray(uint16_t type)
+        : Option(Option::V6, type),
+          values_(0) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+    }
+
+    /// @brief Constructor.
+    ///
+    /// @param type option type.
+    /// @param buf buffer with option data (must not be empty).
+    ///
+    /// @throw isc::OutOfRange if provided buffer is empty or its length
+    /// is not multiple of size of the data type in bytes.
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6IntArray(uint16_t type, const OptionBuffer& buf)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        unpack(buf.begin(), buf.end());
+    }
+
+    /// @brief Constructor.
+    ///
+    /// This constructor creates option from a buffer. This construtor
+    /// may throw exception if \ref unpack function throws during buffer
+    /// parsing.
+    ///
+    /// @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).
+    ///
+    /// @throw isc::OutOfRange if provided buffer is empty or its length
+    /// is not multiple of size of the data type in bytes.
+    /// @throw isc::dhcp::InvalidDataType if data field type provided
+    /// as template parameter is not a supported integer type.
+    Option6IntArray(uint16_t type, OptionBufferConstIter begin,
+                    OptionBufferConstIter end)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-integer type");
+        }
+        unpack(begin, end);
+    }
+
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf buffer (option will be stored here)
+    ///
+    /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    void pack(isc::util::OutputBuffer& buf) {
+        buf.writeUint16(type_);
+        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        for (int i = 0; i < values_.size(); ++i) {
+            // Depending on the data type length we use different utility functions
+            // writeUint16 or writeUint32 which write the data in the network byte
+            // order to the provided buffer. The same functions can be safely used
+            // for either unsiged or signed integers so there is not need to create
+            // special cases for intX_t types.
+            switch (OptionDataTypes<T>::len) {
+            case 1:
+                buf.writeUint8(values_[i]);
+                break;
+            case 2:
+                buf.writeUint16(values_[i]);
+                break;
+            case 4:
+                buf.writeUint32(values_[i]);
+                break;
+            default:
+                isc_throw(dhcp::InvalidDataType, "non-integer type");
+            }
+        }
+        // We don't pack sub-options here because we have array-type option.
+        // We don't allow sub-options in array-type options as there is no
+        // way to distinguish them from the data fields on option reception.
+    }
+
+    /// @brief Parses received buffer
+    ///
+    /// Parses received buffer and returns offset to the first unused byte after
+    /// parsed option.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    ///
+    /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not
+    /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
+    /// because it is checked in a constructor.
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+        if (distance(begin, end) == 0) {
+            isc_throw(OutOfRange, "option " << getType() << " empty");
+        }
+        if (distance(begin, end) % sizeof(T) != 0) {
+            isc_throw(OutOfRange, "option " << getType() << " truncated");
+        }
+        // @todo consider what to do if buffer is longer than data type.
+
+        values_.clear();
+        while (begin != end) {
+            // Depending on the data type length we use different utility functions
+            // readUint16 or readUint32 which read the data laid in the network byte
+            // order from the provided buffer. The same functions can be safely used
+            // for either unsiged or signed integers so there is not need to create
+            // special cases for intX_t types.
+            int data_size_len = OptionDataTypes<T>::len;
+            switch (data_size_len) {
+            case 1:
+                values_.push_back(*begin);
+                break;
+            case 2:
+                values_.push_back(isc::util::readUint16(&(*begin)));
+                break;
+            case 4:
+                values_.push_back(isc::util::readUint32(&(*begin)));
+                break;
+            default:
+                isc_throw(dhcp::InvalidDataType, "non-integer type");
+            }
+            // Use local variable to set a new value for this iterator.
+            // When using OptionDataTypes<T>::len directly some versions
+            // of clang complain about unresolved reference to
+            // OptionDataTypes structure during linking.
+            begin += data_size_len;
+        }
+        // We do not unpack sub-options here because we have array-type option.
+        // Such option have variable number of data fields, thus there is no
+        // way to assess where sub-options start.
+    }
+
+    /// @brief Return collection of option values.
+    ///
+    /// @return collection of values.
+    const std::vector<T>& getValues() const { return (values_); }
+
+    /// @brief Set option values.
+    ///
+    /// @param values collection of values to be set for option.
+    void setValues(const std::vector<T>& values) { values_ = values; }
+
+    /// @brief returns complete length of option
+    ///
+    /// Returns length of this option, including option header and suboptions
+    ///
+    /// @return length of this option
+    virtual uint16_t len() {
+        uint16_t length = OPTION6_HDR_LEN + values_.size() * sizeof(T);
+        // length of all suboptions
+        for (Option::OptionCollection::iterator it = options_.begin();
+             it != options_.end();
+             ++it) {
+            length += (*it).second->len();
+        }
+        return (length);
+    }
+
+private:
+
+    std::vector<T> values_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION6_INT_ARRAY_H_ */
diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h
new file mode 100644
index 0000000..4e8d8a6
--- /dev/null
+++ b/src/lib/dhcp/option_data_types.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2012 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 OPTION_DATA_TYPES_H_
+#define OPTION_DATA_TYPES_H_
+
+#include <exceptions/exceptions.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception to be thrown when invalid type specified as template parameter.
+class InvalidDataType : public Exception {
+public:
+    InvalidDataType(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Trait class for integer data types supported in DHCP option definitions.
+///
+/// This is useful to check whether the type specified as template parameter
+/// is supported by classes like Option6Int, Option6IntArray and some template
+/// factory functions in OptionDefinition class.
+template<typename T>
+struct OptionDataTypes {
+    static const bool valid = false;
+    static const int len = 0;
+};
+
+/// int8_t type is supported.
+template<>
+struct OptionDataTypes<int8_t> {
+    static const bool valid = true;
+    static const int len = 1;
+};
+
+/// int16_t type is supported.
+template<>
+struct OptionDataTypes<int16_t> {
+    static const bool valid = true;
+    static const int len = 2;
+};
+
+/// int32_t type is supported.
+template<>
+struct OptionDataTypes<int32_t> {
+    static const bool valid = true;
+    static const int len = 4;
+};
+
+/// uint8_t type is supported.
+template<>
+struct OptionDataTypes<uint8_t> {
+    static const bool valid = true;
+    static const int len = 1;
+};
+
+/// uint16_t type is supported.
+template<>
+struct OptionDataTypes<uint16_t> {
+    static const bool valid = true;
+    static const int len = 2;
+};
+
+/// uint32_t type is supported.
+template<>
+struct OptionDataTypes<uint32_t> {
+    static const bool valid = true;
+    static const int len = 4;
+};
+
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION_DATA_TYPES_H_ */
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
new file mode 100644
index 0000000..f562316
--- /dev/null
+++ b/src/lib/dhcp/option_definition.cc
@@ -0,0 +1,252 @@
+// Copyright (C) 2012 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 <dhcp/dhcp6.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option6_addrlst.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+
+using namespace std;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+OptionDefinition::DataTypeUtil::DataTypeUtil() {
+    data_types_["empty"] = EMPTY_TYPE;
+    data_types_["boolean"] = BOOLEAN_TYPE;
+    data_types_["int8"] = INT8_TYPE;
+    data_types_["int16"] = INT16_TYPE;
+    data_types_["int32"] = INT32_TYPE;
+    data_types_["uint8"] = UINT8_TYPE;
+    data_types_["uint16"] = UINT16_TYPE;
+    data_types_["uint32"] = UINT32_TYPE;
+    data_types_["ipv4-address"] = IPV4_ADDRESS_TYPE;
+    data_types_["ipv6-address"] = IPV6_ADDRESS_TYPE;
+    data_types_["string"] = STRING_TYPE;
+    data_types_["fqdn"] = FQDN_TYPE;
+    data_types_["record"] = RECORD_TYPE;
+}
+
+OptionDefinition::DataType
+OptionDefinition::DataTypeUtil::getDataType(const std::string& data_type) {
+    std::map<std::string, DataType>::const_iterator data_type_it =
+        data_types_.find(data_type);
+    if (data_type_it != data_types_.end()) {
+        return (data_type_it->second);
+    }
+    return UNKNOWN_TYPE;
+}
+
+OptionDefinition::OptionDefinition(const std::string& name,
+                                 const uint16_t code,
+                                 const std::string& type,
+                                 const bool array_type /* = false */)
+    : name_(name),
+      code_(code),
+      type_(UNKNOWN_TYPE),
+      array_type_(array_type) {
+    // Data type is held as enum value by this class.
+    // Use the provided option type string to get the
+    // corresponding enum value.
+    type_ = DataTypeUtil::instance().getDataType(type);
+}
+
+OptionDefinition::OptionDefinition(const std::string& name,
+                                   const uint16_t code,
+                                   const DataType type,
+                                   const bool array_type /* = false */)
+    : name_(name),
+      code_(code),
+      type_(type),
+      array_type_(array_type) {
+}
+
+void
+OptionDefinition::addRecordField(const std::string& data_type_name) {
+    DataType data_type = DataTypeUtil::instance().getDataType(data_type_name);
+    addRecordField(data_type);
+}
+
+void
+OptionDefinition::addRecordField(const DataType data_type) {
+    if (type_ != RECORD_TYPE) {
+        isc_throw(isc::InvalidOperation, "'record' option type must be used"
+                  " to add data fields to the record");
+    }
+    if (data_type >= UNKNOWN_TYPE) {
+        isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
+    }
+    record_fields_.push_back(data_type);
+}
+
+Option::Factory*
+OptionDefinition::getFactory() const {
+    // @todo This function must be extended to return more factory
+    // functions that create instances of more specialized options.
+    // This requires us to first implement those more specialized
+    // options that will be derived from Option class.
+    if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
+        return (factoryAddrList6);
+    } else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
+        return (factoryAddrList4);
+    } else if (type_ == EMPTY_TYPE) {
+        return (factoryEmpty);
+    } else if (code_ == D6O_IA_NA && haveIA6Format()) {
+        return (factoryIA6);
+    } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
+        return (factoryIAAddr6);
+    } else if (type_ == UINT8_TYPE) {
+        if (array_type_) {
+            return (factoryGeneric);
+        } else {
+            return (factoryInteger<uint8_t>);
+        }
+    } else if (type_ == UINT16_TYPE) {
+        if (array_type_) {
+            return (factoryIntegerArray<uint16_t>);
+        } else {
+            return (factoryInteger<uint16_t>);
+        }
+    } else if (type_ == UINT32_TYPE) {
+        if (array_type_) {
+            return (factoryIntegerArray<uint32_t>);
+        } else {
+            return (factoryInteger<uint32_t>);
+        }
+    }
+    // Factory generic returns instance of Option class. However, once we
+    // implement CustomOption class we may want to return factory function
+    // that will create instance of CustomOption rather than Option.
+    // CustomOption will allow to access particular data fields within the
+    // option rather than raw data buffer.
+    return (factoryGeneric);
+}
+
+void
+OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
+                                      const Option::Universe actual_universe) {
+    if (expected_universe != actual_universe) {
+        isc_throw(isc::BadValue, "invalid universe specified for the option");
+    }
+}
+
+void
+OptionDefinition::validate() const {
+    // Option name must not be empty.
+    if (name_.empty()) {
+        isc_throw(isc::BadValue, "option name must not be empty");
+    }
+    // Option name must not contain spaces.
+    if (name_.find(" ") != string::npos) {
+        isc_throw(isc::BadValue, "option name must not contain spaces");
+    }
+    // Unsupported option types are not allowed.
+    if (type_ >= UNKNOWN_TYPE) {
+        isc_throw(isc::OutOfRange, "option type value " << type_
+                  << " is out of range");
+    }
+}
+
+bool
+OptionDefinition::haveIAx6Format(OptionDefinition::DataType first_type) const {
+   return (haveType(RECORD_TYPE) &&
+           record_fields_.size() == 3 &&
+           record_fields_[0] == first_type &&
+           record_fields_[1] == UINT32_TYPE &&
+           record_fields_[2] == UINT32_TYPE);
+}
+
+bool
+OptionDefinition::haveIA6Format() const {
+    // Expect that IA_NA option format is defined as record.
+    // Although it consists of 3 elements of the same (uint32)
+    // type it can't be defined as array of uint32 elements because
+    // arrays do not impose limitations on number of elements in
+    // the array while this limitation is needed for IA_NA - need
+    // exactly 3 elements.
+    return (haveIAx6Format(UINT32_TYPE));
+}
+
+bool
+OptionDefinition::haveIAAddr6Format() const {
+    return (haveIAx6Format(IPV6_ADDRESS_TYPE));
+}
+
+OptionPtr
+OptionDefinition::factoryAddrList4(Option::Universe u, uint16_t type,
+                                   const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V4);
+    boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, buf.begin(),
+                                                                buf.begin() + buf.size()));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryAddrList6(Option::Universe u, uint16_t type,
+                                   const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V6);
+    boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, buf.begin(),
+                                                                buf.begin() + buf.size()));
+    return (option);
+}
+
+
+OptionPtr
+OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    if (buf.size() > 0) {
+        isc_throw(isc::BadValue, "input option buffer must be empty"
+                  " when creating empty option instance");
+    }
+    OptionPtr option(new Option(u, type));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    OptionPtr option(new Option(u, type, buf));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryIA6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V6);
+    if (buf.size() != Option6IA::OPTION6_IA_LEN) {
+        isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
+                  << Option6IA::OPTION6_IA_LEN << " bytes");
+    }
+    boost::shared_ptr<Option6IA> option(new Option6IA(type, buf.begin(),
+                                                      buf.begin() + buf.size()));
+    return (option);
+}
+
+OptionPtr
+OptionDefinition::factoryIAAddr6(Option::Universe u, uint16_t type, const OptionBuffer& buf) {
+    sanityCheckUniverse(u, Option::V6);
+    if (buf.size() != Option6IAAddr::OPTION6_IAADDR_LEN) {
+        isc_throw(isc::OutOfRange, "input option buffer has invalid size, expeted "
+                  << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
+    }
+    boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, buf.begin(),
+                                                      buf.begin() + buf.size()));
+    return (option);
+}
+
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
new file mode 100644
index 0000000..c274ce9
--- /dev/null
+++ b/src/lib/dhcp/option_definition.h
@@ -0,0 +1,383 @@
+// Copyright (C) 2012 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 OPTION_DEFINITION_H_
+#define OPTION_DEFINITION_H_
+
+#include <dhcp/option_data_types.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp/option.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Base class representing a DHCP option definition.
+///
+/// This is a base class representing a DHCP option definition, which describes
+/// the format of the option. In particular, it defines:
+/// - option name,
+/// - option code,
+/// - data fields order and their types,
+/// - sub options space that the particular option encapsulates.
+///
+/// The option type specifies the data type(s) which an option conveys.  If
+/// this is a single value the option type points to the data type of the
+/// value. For example, DHCPv6 option 8 comprises a two-byte option code, a
+/// two-byte option length and two-byte field that carries a uint16 value
+/// (RFC 3315 - http://ietf.org/rfc/rfc3315.txt).  In such a case, the option
+/// type is defined as "uint16".
+///
+/// When the option has a more complex structure, the option type may be
+/// defined as "array", "record" or even "array of records".
+///
+/// Array types should be used when the option contains multiple contiguous
+/// data values of the same type laid. For example, DHCPv6 option 6 includes
+/// multiple fields holding uint16 codes of requested DHCPv6 options (RFC 3315).
+/// Such an option can be represented with this class by setting the option
+/// type to "uint16" and the array indicator (array_type) to true.  The number
+/// of elements in the array is effectively unlimited (although it is actually
+/// limited by the maximal DHCPv6 option length).
+///
+/// Should the option comprise data fields of different types, the "record"
+/// option type is used. In such cases the data field types within the record
+/// are specified using \ref OptionDefinition::addRecordField.
+///
+/// When the OptionDefinition object has been sucessfully created, it can be
+/// queried to return the appropriate option factory function for the specified
+/// specified option format. There are a number of "standard" factory functions
+/// that cover well known (common) formats.  If the particular format does not
+/// match any common format the generic factory function is returned.
+///
+/// The following data type strings are supported:
+/// - "empty" (option does not contain data fields)
+/// - "boolean"
+/// - "int8"
+/// - "int16"
+/// - "int32"
+/// - "uint8"
+/// - "uint16"
+/// - "uint32"
+/// - "ipv4-address" (IPv4 Address)
+/// - "ipv6-address" (IPV6 Address)
+/// - "string"
+/// - "fqdn" (fully qualified name)
+/// - "record" (set of data fields of different types)
+///
+/// @todo Extend the comment to describe "generic factories".
+/// @todo Extend this class to use custom namespaces.
+/// @todo Extend this class with more factory functions.
+class OptionDefinition {
+public:
+
+    /// Data types of DHCP option fields.
+    enum DataType {
+        EMPTY_TYPE,
+        BOOLEAN_TYPE,
+        INT8_TYPE,
+        INT16_TYPE,
+        INT32_TYPE,
+        UINT8_TYPE,
+        UINT16_TYPE,
+        UINT32_TYPE,
+        IPV4_ADDRESS_TYPE,
+        IPV6_ADDRESS_TYPE,
+        STRING_TYPE,
+        FQDN_TYPE,
+        RECORD_TYPE,
+        UNKNOWN_TYPE
+    };
+
+    /// List of fields within the record.
+    typedef std::vector<DataType> RecordFieldsCollection;
+    /// Const iterator for record data fields.
+    typedef std::vector<DataType>::const_iterator RecordFieldsConstIter;
+
+private:
+
+    /// @brief Utility class for operations on DataTypes.
+    ///
+    /// This class is implemented as the singleton because the list of
+    /// supported data types need only be loaded only once into memory as it
+    /// can persist for all option definitions.
+    ///
+    /// @todo This class can be extended to return the string value
+    /// representing the data type from the enum value.
+    class DataTypeUtil {
+    public:
+
+        /// @brief Return the sole instance of this class.
+        ///
+        /// @return instance of this class.
+        static DataTypeUtil& instance() {
+            static DataTypeUtil instance;
+            return (instance);
+        }
+
+        /// @brief Convert type given as string value to option data type.
+        ///
+        /// @param data_type_name data type string.
+        ///
+        /// @return option data type.
+        DataType getDataType(const std::string& data_type_name);
+
+    private:
+        /// @brief Private constructor.
+        ///
+        /// Constructor initializes the internal data structures, e.g.
+        /// mapping between data type name and the corresponding enum.
+        /// This constructor is private to ensure that exactly one
+        /// instance of this class can be created using \ref instance
+        /// function.
+        DataTypeUtil();
+
+        /// Map of data types, maps name of the type to enum value.
+        std::map<std::string, DataType> data_types_;
+    };
+
+public:
+    /// @brief Constructor.
+    ///
+    /// @param name option name.
+    /// @param code option code.
+    /// @param type option data type as string.
+    /// @param array_type array indicator, if true it indicates that the
+    /// option fields are the array.
+    OptionDefinition(const std::string& name,
+                     const uint16_t code,
+                     const std::string& type,
+                     const bool array_type = false);
+
+    /// @brief Constructor.
+    ///
+    /// @param name option name.
+    /// @param code option code.
+    /// @param type option data type.
+    /// @param array_type array indicator, if true it indicates that the
+    /// option fields are the array.
+    OptionDefinition(const std::string& name,
+                     const uint16_t code,
+                     const DataType type,
+                     const bool array_type = false);
+
+    /// @brief Adds data field to the record.
+    ///
+    /// @param data_type_name name of the data type for the field.
+    ///
+    /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
+    /// @throw isc::BadValue if specified invalid data type.
+    void addRecordField(const std::string& data_type_name);
+
+    /// @brief Adds data field to the record.
+    ///
+    /// @param data_type data type for the field.
+    ///
+    /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
+    /// @throw isc::BadValue if specified invalid data type.
+    void addRecordField(const DataType data_type);
+
+    /// @brief Return array type indicator.
+    ///
+    /// The method returns the bool value to indicate whether the option is a
+    /// a single value or an array of values.
+    ///
+    /// @return true if option comprises an array of values.
+    bool getArrayType() const { return (array_type_); }
+
+    /// @brief Return option code.
+    ///
+    /// @return option code.
+    uint16_t getCode() const { return (code_); }
+
+    /// @brief Return factory function for the given definition.
+    ///
+    /// @return pointer to factory function.
+    Option::Factory* getFactory() const;
+
+    /// @brief Return option name.
+    ///
+    /// @return option name.
+    const std::string& getName() const { return (name_); }
+
+    /// @brief Return list of record fields.
+    ///
+    /// @return list of record fields.
+    const RecordFieldsCollection& getRecordFields() const { return (record_fields_); }
+
+    /// @brief Return option data type.
+    ///
+    /// @return option data type.
+    DataType getType() const { return (type_); };
+
+    /// @brief Check if the option definition is valid.
+    ///
+    /// @throw isc::OutOfRange if invalid option type was specified.
+    /// @throw isc::BadValue if invalid option name was specified,
+    /// e.g. empty or containing spaces.
+    void validate() const;
+
+    /// @brief Check if specified format is IA_NA option format.
+    ///
+    /// @return true if specified format is IA_NA option format.
+    bool haveIA6Format() const;
+
+    /// @brief Check if specified format is IAADDR option format.
+    ///
+    /// @return true if specified format is IAADDR option format.
+    bool haveIAAddr6Format() const;
+
+    /// @brief Factory to create option with address list.
+    ///
+    /// @param u universe (must be V4).
+    /// @param type option type.
+    /// @param buf option buffer with a list of IPv4 addresses.
+    ///
+    /// @throw isc::OutOfRange if length of the provided option buffer
+    /// is not multiple of IPV4 address length.
+    static OptionPtr factoryAddrList4(Option::Universe u, uint16_t type,
+                                      const OptionBuffer& buf);
+
+    /// @brief Factory to create option with address list.
+    ///
+    /// @param u universe (must be V6).
+    /// @param type option type.
+    /// @param buf option buffer with a list of IPv6 addresses.
+    ///
+    /// @throw isc::OutOfaRange if length of provided option buffer
+    /// is not multiple of IPV6 address length.
+    static OptionPtr factoryAddrList6(Option::Universe u, uint16_t type,
+                                      const OptionBuffer& buf);
+
+    /// @brief Empty option factory.
+    ///
+    /// @param u universe (V6 or V4).
+    /// @param type option type.
+    /// @param buf option buffer (must be empty).
+    static OptionPtr factoryEmpty(Option::Universe u, uint16_t type,
+                                  const OptionBuffer& buf);
+
+    /// @brief Factory to create generic option.
+    ///
+    /// @param u universe (V6 or V4).
+    /// @param type option type.
+    /// @param buf option buffer.
+    static OptionPtr factoryGeneric(Option::Universe u, uint16_t type,
+                                    const OptionBuffer& buf);
+
+    /// @brief Factory for IA-type of option.
+    ///
+    /// @param u universe (must be V6).
+    /// @param type option type.
+    /// @param buf option buffer.
+    ///
+    /// @throw isc::OutOfRange if provided option buffer is too short or
+    /// too long. Expected size is 12 bytes.
+    /// @throw isc::BadValue if specified universe value is not V6.
+    static OptionPtr factoryIA6(Option::Universe u, uint16_t type,
+                                const OptionBuffer& buf);
+
+    /// @brief Factory for IAADDR-type of option.
+    ///
+    /// @param u universe (must be V6).
+    /// @param type option type.
+    /// @param buf option buffer.
+    ///
+    /// @throw isc::OutOfRange if provided option buffer is too short or
+    /// too long. Expected size is 24 bytes.
+    /// @throw isc::BadValue if specified universe value is not V6.
+    static OptionPtr factoryIAAddr6(Option::Universe u, uint16_t type,
+                                const OptionBuffer& buf);
+
+    /// @brief Factory function to create option with integer value.
+    ///
+    /// @param type option type.
+    /// @param buf option buffer.
+    /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
+    ///
+    /// @throw isc::OutOfRange if provided option buffer length is invalid.
+    template<typename T>
+    static OptionPtr factoryInteger(Option::Universe, uint16_t type, const OptionBuffer& buf) {
+        if (buf.size() > sizeof(T)) {
+            isc_throw(isc::OutOfRange, "provided option buffer is too large, expected: "
+                      << sizeof(T) << " bytes");
+        }
+        OptionPtr option(new Option6Int<T>(type, buf.begin(), buf.end()));
+        return (option);
+    }
+
+    /// @brief Factory function to create option with array of integer values.
+    ///
+    /// @param type option type.
+    /// @param buf option buffer.
+    /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
+    ///
+    /// @throw isc::OutOfRange if provided option buffer length is invalid.
+    template<typename T>
+    static OptionPtr factoryIntegerArray(Option::Universe, uint16_t type, const OptionBuffer& buf) {
+        if (buf.size() == 0) {
+            isc_throw(isc::OutOfRange, "option buffer length must be greater than zero");
+        } else if (buf.size() % OptionDataTypes<T>::len != 0) {
+            isc_throw(isc::OutOfRange, "option buffer length must be multiple of "
+                      << OptionDataTypes<T>::len << " bytes");
+        }
+        OptionPtr option(new Option6IntArray<T>(type, buf.begin(), buf.end()));
+        return (option);
+    }
+
+private:
+
+    /// @brief Check if specified option format is a record with 3 fields
+    /// where first one is custom, and two others are uint32.
+    ///
+    /// This is a helper function for functions that detect IA_NA and IAAddr
+    /// option formats.
+    ///
+    /// @param first_type type of the first data field.
+    ///
+    /// @return true if actual option format matches expected format.
+    bool haveIAx6Format(const OptionDefinition::DataType first_type) const;
+
+    /// @brief Check if specified type matches option definition type.
+    ///
+    /// @return true if specified type matches option definition type.
+    inline bool haveType(const DataType type) const {
+        return (type == type_);
+    }
+
+    /// @brief Sanity check universe value.
+    ///
+    /// @param expected_universe expected universe value.
+    /// @param actual_universe actual universe value.
+    ///
+    /// @throw isc::BadValue if expected universe and actual universe don't match.
+   static inline void sanityCheckUniverse(const Option::Universe expected_universe,
+                                          const Option::Universe actual_universe); 
+
+    /// Option name.
+    std::string name_;
+    /// Option code.
+    uint16_t code_;
+    /// Option data type.
+    DataType type_;
+    /// Indicates wheter option is a single value or array.
+    bool array_type_;
+    /// Collection of data fields within the record.
+    RecordFieldsCollection record_fields_;
+};
+
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index a15d957..206116f 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -33,7 +33,10 @@ libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
 libdhcp___unittests_SOURCES += option6_ia_unittest.cc
 libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
 libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
+libdhcp___unittests_SOURCES += option6_int_unittest.cc
+libdhcp___unittests_SOURCES += option6_int_array_unittest.cc
 libdhcp___unittests_SOURCES += option_unittest.cc
+libdhcp___unittests_SOURCES += option_definition_unittest.cc
 libdhcp___unittests_SOURCES += pkt6_unittest.cc
 libdhcp___unittests_SOURCES += pkt4_unittest.cc
 libdhcp___unittests_SOURCES += duid_unittest.cc
diff --git a/src/lib/dhcp/tests/option6_int_array_unittest.cc b/src/lib/dhcp/tests/option6_int_array_unittest.cc
new file mode 100644
index 0000000..581d4e1
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_int_array_unittest.cc
@@ -0,0 +1,420 @@
+// Copyright (C) 2012 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_int_array.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Option6IntArray test class.
+class Option6IntArrayTest : public ::testing::Test {
+public:
+    /// @brief Constructor.
+    ///
+    /// Initializes the option buffer with some data.
+    Option6IntArrayTest(): buf_(255), out_buf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
+    }
+
+    /// @brief Test parsing buffer into array of int8_t or uint8_t values.
+    ///
+    /// @warning this function does not perform type check. Make
+    /// sure that only int8_t or uint8_t type is used.
+    ///
+    /// @tparam T int8_t or uint8_t.
+    template<typename T>
+    void bufferToIntTest8() {
+        // Create option that conveys array of multiple uint8_t or int8_t values.
+        // In fact there is no need to use this template class for array
+        // of uint8_t values because Option class is sufficient - it
+        // returns the buffer which is actually the array of uint8_t.
+        // However, since we allow using uint8_t types with this template
+        // class we have to test it here.
+        boost::shared_ptr<Option6IntArray<T> > opt;
+        const int opt_len = 10;
+        const uint16_t opt_code = 80;
+
+        // Constructor throws exception if provided buffer is empty.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            isc::OutOfRange
+        );
+
+        // Provided buffer is not empty so it should not throw exception.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<
+                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
+                                                            buf_.begin() + opt_len))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        // Option should return the collection of int8_t or uint8_t values that
+        // we can match with the buffer we used to create the option.
+        std::vector<T> values = opt->getValues();
+        // We need to copy values from the buffer to apply sign if signed
+        // type is used.
+        std::vector<T> reference_values;
+        for (int i = 0; i < opt_len; ++i) {
+            // Values have been read from the buffer in network
+            // byte order. We put them back in the same order here.
+            reference_values.push_back(static_cast<T>(buf_[i]));
+        }
+
+        // Compare the values against the reference buffer.
+        ASSERT_EQ(opt_len, values.size());
+        EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
+                               + opt_len, values.begin()));
+
+        // test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 10 bytes.
+        EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(opt_code, opt->getType());
+        // The total length is 10 bytes for data and 4 bytes for header.
+        ASSERT_EQ(14, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(opt_code, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(10, out.readUint16());
+        // if data is correct
+        std::vector<uint8_t> out_data;
+        ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+        ASSERT_EQ(opt_len, out_data.size());
+        EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+    }
+
+    /// @brief Test parsing buffer into array of int16_t or uint16_t values.
+    ///
+    /// @warning this function does not perform type check. Make
+    /// sure that only int16_t or uint16_t type is used.
+    ///
+    /// @tparam T int16_t or uint16_t.
+    template<typename T>
+    void bufferToIntTest16() {
+        // Create option that conveys array of multiple uint16_t or int16_t values.
+        boost::shared_ptr<Option6IntArray<T> > opt;
+        const int opt_len = 20;
+        const uint16_t opt_code = 81;
+
+        // Constructor throws exception if provided buffer is empty.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            isc::OutOfRange
+        );
+
+        // Constructor throws exception if provided buffer's length is not
+        // multiple of 2-bytes.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 5),
+            isc::OutOfRange
+        );
+
+        // Now the buffer length is correct.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<
+                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
+                                                            buf_.begin() + opt_len))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        // Option should return vector of uint16_t values which should be
+        // constructed from the buffer we provided.
+        std::vector<T> values = opt->getValues();
+        ASSERT_EQ(opt_len, values.size() * sizeof(T));
+        // Create reference values from the buffer so as we can
+        // simply compare two vectors.
+        std::vector<T> reference_values;
+        for (int i = 0; i < opt_len; i += 2) {
+            reference_values.push_back((buf_[i] << 8) |
+                                       buf_[i + 1]);
+        }
+        EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
+                               values.begin()));
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 20 bytes.
+        EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(opt_code, opt->getType());
+        // The total length is 20 bytes for data and 4 bytes for header.
+        ASSERT_EQ(24, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(opt_code, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(20, out.readUint16());
+        // if data is correct
+        std::vector<uint8_t> out_data;
+        ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+        ASSERT_EQ(opt_len, out_data.size());
+        EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+    }
+
+    /// @brief Test parsing buffer into array of int32_t or uint32_t values.
+    ///
+    /// @warning this function does not perform type check. Make
+    /// sure that only int32_t or uint32_t type is used.
+    ///
+    /// @tparam T int32_t or uint32_t.
+    template<typename T>
+    void bufferToIntTest32() {
+        // Create option that conveys array of multiple uint16_t values.
+        boost::shared_ptr<Option6IntArray<T> > opt;
+        const int opt_len = 40;
+        const uint16_t opt_code = 82;
+
+        // Constructor throws exception if provided buffer is empty.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            isc::OutOfRange
+        );
+
+        // Constructor throws exception if provided buffer's length is not
+        // multiple of 4-bytes.
+        EXPECT_THROW(
+            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 9),
+            isc::OutOfRange
+        );
+
+        // Now the buffer length is correct.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<
+                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
+                                                            buf_.begin() + opt_len))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(opt_code, opt->getType());
+        // Option should return vector of uint32_t values which should be
+        // constructed from the buffer we provided.
+        std::vector<T> values = opt->getValues();
+        ASSERT_EQ(opt_len, values.size() * sizeof(T));
+        // Create reference values from the buffer so as we can
+        // simply compare two vectors.
+        std::vector<T> reference_values;
+        for (int i = 0; i < opt_len; i += 4) {
+            reference_values.push_back((buf_[i] << 24) |
+                                       (buf_[i + 1] << 16 & 0x00FF0000) |
+                                       (buf_[i + 2] << 8 & 0xFF00) |
+                                       (buf_[i + 3] & 0xFF));
+        }
+        EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
+                               values.begin()));
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 40 bytes.
+        EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(opt_code, opt->getType());
+        // The total length is 40 bytes for data and 4 bytes for header.
+        ASSERT_EQ(44, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(opt_code, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(40, out.readUint16());
+        // if data is correct
+        std::vector<uint8_t> out_data;
+        ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+        ASSERT_EQ(opt_len, out_data.size());
+        EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+    }
+
+
+    OptionBuffer buf_;     ///< Option buffer
+    OutputBuffer out_buf_; ///< Output buffer
+};
+
+/// @todo: below, there is a bunch of tests for options that
+/// convey unsigned values. We should maybe extend these tests for
+/// signed types too.
+
+TEST_F(Option6IntArrayTest, useInvalidType) {
+    const uint16_t opt_code = 80;
+    EXPECT_THROW(
+        boost::scoped_ptr<
+            Option6IntArray<bool> >(new Option6IntArray<bool>(opt_code, OptionBuffer(5))),
+        InvalidDataType
+    );
+
+    EXPECT_THROW(
+        boost::scoped_ptr<
+            Option6IntArray<int64_t> >(new Option6IntArray<int64_t>(opt_code,
+                                                                    OptionBuffer(10))),
+        InvalidDataType
+    );
+
+}
+
+TEST_F(Option6IntArrayTest, bufferToUint8) {
+    bufferToIntTest8<uint8_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToInt8) {
+    bufferToIntTest8<int8_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToUint16) {
+    bufferToIntTest16<uint16_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToInt16) {
+    bufferToIntTest16<int16_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToUint32) {
+    bufferToIntTest32<uint32_t>();
+}
+
+TEST_F(Option6IntArrayTest, bufferToInt32) {
+    bufferToIntTest32<int32_t>();
+}
+
+TEST_F(Option6IntArrayTest, setValuesUint8) {
+    const uint16_t opt_code = 100;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<uint8_t> > opt(new Option6IntArray<uint8_t>(opt_code));
+    // Initialize vector with some data and pass to the option.
+    std::vector<uint8_t> values;
+    for (int i = 0; i < 10; ++i) {
+        values.push_back(numeric_limits<uint8_t>::max() - i);
+    }
+    opt->setValues(values);
+
+    // Check if universe, option type and data was set correctly.
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(opt_code, opt->getType());
+    std::vector<uint8_t> returned_values = opt->getValues();
+    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesInt8) {
+    const uint16_t opt_code = 100;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<int8_t> > opt(new Option6IntArray<int8_t>(opt_code));
+    // Initialize vector with some data and pass to the option.
+    std::vector<int8_t> values;
+    for (int i = 0; i < 10; ++i) {
+        values.push_back(numeric_limits<int8_t>::min() + i);
+    }
+    opt->setValues(values);
+
+    // Check if universe, option type and data was set correctly.
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(opt_code, opt->getType());
+    std::vector<int8_t> returned_values = opt->getValues();
+    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesUint16) {
+    const uint16_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<uint16_t> > opt(new Option6IntArray<uint16_t>(opt_code));
+    // Initialize vector with some data and pass to the option.
+    std::vector<uint16_t> values;
+    for (int i = 0; i < 10; ++i) {
+        values.push_back(numeric_limits<uint16_t>::max() - i);
+    }
+    opt->setValues(values);
+
+    // Check if universe, option type and data was set correctly.
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(opt_code, opt->getType());
+    std::vector<uint16_t> returned_values = opt->getValues();
+    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesInt16) {
+    const uint16_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<int16_t> > opt(new Option6IntArray<int16_t>(opt_code));
+    // Initialize vector with some data and pass to the option.
+    std::vector<int16_t> values;
+    for (int i = 0; i < 10; ++i) {
+        values.push_back(numeric_limits<int16_t>::min() + i);
+    }
+    opt->setValues(values);
+
+    // Check if universe, option type and data was set correctly.
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(opt_code, opt->getType());
+    std::vector<int16_t> returned_values = opt->getValues();
+    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesUint32) {
+    const uint32_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<uint32_t> > opt(new Option6IntArray<uint32_t>(opt_code));
+    // Initialize vector with some data and pass to the option.
+    std::vector<uint32_t> values;
+    for (int i = 0; i < 10; ++i) {
+        values.push_back(numeric_limits<uint32_t>::max() - i);
+    }
+    opt->setValues(values);
+
+    // Check if universe, option type and data was set correctly.
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(opt_code, opt->getType());
+    std::vector<uint32_t> returned_values = opt->getValues();
+    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(Option6IntArrayTest, setValuesInt32) {
+    const uint32_t opt_code = 101;
+    // Create option with empty vector of values.
+    boost::shared_ptr<Option6IntArray<int32_t> > opt(new Option6IntArray<int32_t>(opt_code));
+    // Initialize vector with some data and pass to the option.
+    std::vector<int32_t> values;
+    for (int i = 0; i < 10; ++i) {
+        values.push_back(numeric_limits<int32_t>::min() + i);
+    }
+    opt->setValues(values);
+
+    // Check if universe, option type and data was set correctly.
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(opt_code, opt->getType());
+    std::vector<int32_t> returned_values = opt->getValues();
+    EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option6_int_unittest.cc b/src/lib/dhcp/tests/option6_int_unittest.cc
new file mode 100644
index 0000000..2aceed8
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_int_unittest.cc
@@ -0,0 +1,410 @@
+// Copyright (C) 2012 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_int.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Option6Int test class.
+class Option6IntTest : public ::testing::Test {
+public:
+    /// @brief Constructor.
+    ///
+    /// Initializes the option buffer with some data.
+    Option6IntTest(): buf_(255), out_buf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
+    }
+
+    /// @brief Basic test for int8 and uint8 types.
+    ///
+    /// @note this function does not perform type check. Make
+    /// sure that only int8_t or uint8_t type is used.
+    ///
+    /// @tparam T int8_t or uint8_t.
+    template<typename T>
+    void basicTest8() {
+        // Create option that conveys single 8 bit integer value.
+        boost::shared_ptr<Option6Int<T> > opt;
+        // Initialize buffer with this value.
+        buf_[0] = 0xa1;
+        // Constructor may throw in case provided buffer is too short.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_PREFERENCE,
+                                                                      buf_.begin(),
+                                                                      buf_.end()))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+        // Option should return the same value that we initialized the first
+        // byte of the buffer with.
+        EXPECT_EQ(static_cast<T>(0xa1), opt->getValue());
+
+        // test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 1 byte.
+        EXPECT_EQ(1, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+        // The total length is 1 byte for data and 4 bytes for header.
+        EXPECT_EQ(5, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(D6O_PREFERENCE, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(1, out.readUint16());
+        // if data is correct
+        EXPECT_EQ(0xa1, out.readUint8() );
+    }
+
+    /// @brief Basic test for int16 and uint16 types.
+    ///
+    /// @note this function does not perform type check. Make
+    /// sure that only int16_t or uint16_t type is used.
+    ///
+    /// @tparam T int16_t or uint16_t.
+    template<typename T>
+    void basicTest16() {
+        // Create option that conveys single 16-bit integer value.
+        boost::shared_ptr<Option6Int<T> > opt;
+        // Initialize buffer with uint16_t value.
+        buf_[0] = 0xa1;
+        buf_[1] = 0xa2;
+        // Constructor may throw in case provided buffer is too short.
+        ASSERT_NO_THROW(
+            opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_ELAPSED_TIME,
+                                                                      buf_.begin(),
+                                                                      buf_.end()))
+        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+        // Option should return the value equal to the contents of first
+        // and second byte of the buffer.
+        EXPECT_EQ(static_cast<T>(0xa1a2), opt->getValue());
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 2 bytes.
+        EXPECT_EQ(2, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+        // The total length is 2 byte for data and 4 bytes for header.
+        EXPECT_EQ(6, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(D6O_ELAPSED_TIME, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(2, out.readUint16());
+        // if data is correct
+        EXPECT_EQ(0xa1a2, out.readUint16() );
+    }
+
+    /// @brief Basic test for int32 and uint32 types.
+    ///
+    /// @note this function does not perform type check. Make
+    /// sure that only int32_t or uint32_t type is used.
+    ///
+    /// @tparam T int32_t or uint32_t.
+    template<typename T>
+    void basicTest32() {
+        // Create option that conveys single 32-bit integer value.
+        boost::shared_ptr<Option6Int<T> > opt;
+        // Initialize buffer with 32-bit integer value.
+        buf_[0] = 0xa1;
+        buf_[1] = 0xa2;
+        buf_[2] = 0xa3;
+        buf_[3] = 0xa4;
+        // Constructor may throw in case provided buffer is too short.
+        ASSERT_NO_THROW(
+                        opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_CLT_TIME,
+                                                                                  buf_.begin(),
+                                                                                  buf_.end()))
+                        );
+
+        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+        // Option should return the value equal to the value made of
+        // first 4 bytes of the buffer.
+        EXPECT_EQ(static_cast<T>(0xa1a2a3a4), opt->getValue());
+
+        // Test for pack()
+        opt->pack(out_buf_);
+
+        // Data length is 4 bytes.
+        EXPECT_EQ(4, opt->len() - opt->getHeaderLen());
+        EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+        // The total length is 4 bytes for data and 4 bytes for header.
+        EXPECT_EQ(8, out_buf_.getLength());
+
+        // Check if pack worked properly:
+        InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+        // if option type is correct
+        EXPECT_EQ(D6O_CLT_TIME, out.readUint16());
+        // if option length is correct
+        EXPECT_EQ(4, out.readUint16());
+        // if data is correct
+        EXPECT_EQ(0xa1a2a3a4, out.readUint32());
+    }
+
+    OptionBuffer buf_;     ///< Option buffer
+    OutputBuffer out_buf_; ///< Output buffer
+};
+
+/// @todo: below, there is a bunch of tests for options that
+/// convey unsigned value. We should maybe extend these tests for
+/// signed types too.
+
+TEST_F(Option6IntTest, useInvalidType) {
+    EXPECT_THROW(
+        boost::scoped_ptr<Option6Int<bool> >(new Option6Int<bool>(D6O_ELAPSED_TIME, 10)),
+        InvalidDataType
+    );
+
+    EXPECT_THROW(
+        boost::scoped_ptr<Option6Int<int64_t> >(new Option6Int<int64_t>(D6O_ELAPSED_TIME, 10)),
+        InvalidDataType
+    );
+
+}
+
+TEST_F(Option6IntTest, basicUint8) {
+    basicTest8<uint8_t>();
+}
+
+TEST_F(Option6IntTest, basicUint16) {
+    basicTest16<uint16_t>();
+}
+
+TEST_F(Option6IntTest, basicUint32) {
+    basicTest32<uint32_t>();
+}
+
+TEST_F(Option6IntTest, basicInt8) {
+    basicTest8<int8_t>();
+}
+
+TEST_F(Option6IntTest, basicInt16) {
+    basicTest16<int16_t>();
+}
+
+TEST_F(Option6IntTest, basicInt32) {
+    basicTest32<int32_t>();
+}
+
+TEST_F(Option6IntTest, setValueUint8) {
+    boost::shared_ptr<Option6Int<uint8_t> > opt(new Option6Int<uint8_t>(D6O_PREFERENCE, 123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(123, opt->getValue());
+    // Override the value.
+    opt->setValue(111);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(111, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueInt8) {
+    boost::shared_ptr<Option6Int<int8_t> > opt(new Option6Int<int8_t>(D6O_PREFERENCE, -123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(-123, opt->getValue());
+    // Override the value.
+    opt->setValue(-111);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(-111, opt->getValue());
+}
+
+
+TEST_F(Option6IntTest, setValueUint16) {
+    boost::shared_ptr<Option6Int<uint16_t> > opt(new Option6Int<uint16_t>(D6O_ELAPSED_TIME, 123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(123, opt->getValue());
+    // Override the value.
+    opt->setValue(0x0102);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(0x0102, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueInt16) {
+    boost::shared_ptr<Option6Int<int16_t> > opt(new Option6Int<int16_t>(D6O_ELAPSED_TIME, -16500));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(-16500, opt->getValue());
+    // Override the value.
+    opt->setValue(-20100);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(-20100, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueUint32) {
+    boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(D6O_CLT_TIME, 123));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(123, opt->getValue());
+    // Override the value.
+    opt->setValue(0x01020304);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(0x01020304, opt->getValue());
+}
+
+TEST_F(Option6IntTest, setValueint32) {
+    boost::shared_ptr<Option6Int<int32_t> > opt(new Option6Int<int32_t>(D6O_CLT_TIME, -120100));
+    // Check if constructor intitialized the option value correctly.
+    EXPECT_EQ(-120100, opt->getValue());
+    // Override the value.
+    opt->setValue(-125000);
+
+    EXPECT_EQ(Option::V6, opt->getUniverse());
+    EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+    // Check if the value has been overriden.
+    EXPECT_EQ(-125000, opt->getValue());
+}
+
+TEST_F(Option6IntTest, packSuboptions) {
+    uint16_t opt_code = 80;
+
+    boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(opt_code, 0x01020304));
+    OptionPtr sub1(new Option(Option::V6, 0xcafe));
+
+    boost::shared_ptr<Option6IAAddr> addr1(
+        new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000));
+
+    opt->addOption(sub1);
+    opt->addOption(addr1);
+
+    ASSERT_EQ(28, addr1->len());
+    ASSERT_EQ(4, sub1->len());
+    ASSERT_EQ(40, opt->len());
+
+    uint8_t expected[] = {
+        opt_code / 256, opt_code % 256, // type
+        0, 36, // length
+        0x01, 0x02, 0x03, 0x04, // uint32_t value
+
+        // iaaddr suboption
+        D6O_IAADDR / 256, D6O_IAADDR % 256, // type
+        0, 24, // len
+        0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+        0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+        0, 0, 0x50, 0, // preferred-lifetime
+        0, 0, 0x70, 0, // valid-lifetime
+
+        // suboption
+        0xca, 0xfe, // type
+        0, 0 // len
+    };
+
+    // Create on-wire format of option and suboptions.
+    opt->pack(out_buf_);
+    // Compare the on-wire data with the reference buffer.
+    ASSERT_EQ(40, out_buf_.getLength());
+    EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40));
+}
+
+
+TEST_F(Option6IntTest, unpackSuboptions) {
+    // Create some dummy option.
+    const uint16_t opt_code = 80;
+    // Prepare reference data.
+    uint8_t expected[] = {
+        opt_code / 256, opt_code % 256, // type
+        0, 34, // length
+        0x01, 0x02, // uint16_t value
+
+        // iaaddr suboption
+        D6O_IAADDR / 256, D6O_IAADDR % 256, // type
+        0, 24, // len
+        0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+        0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+        0, 0, 0x50, 0, // preferred-lifetime
+        0, 0, 0x70, 0, // valid-lifetime
+
+        // suboption
+        0xca, 0xfe, // type
+        0, 0 // len
+    };
+    ASSERT_EQ(38, sizeof(expected));
+
+    memcpy(&buf_[0], expected, sizeof(expected));
+
+    boost::shared_ptr<Option6Int<uint16_t> > opt;
+    EXPECT_NO_THROW(
+        opt = boost::shared_ptr<
+            Option6Int<uint16_t> >(new Option6Int<uint16_t>(opt_code, buf_.begin() + 4,
+                                                            buf_.begin() + sizeof(expected)));
+    );
+    ASSERT_TRUE(opt);
+
+    EXPECT_EQ(opt_code, opt->getType());
+    EXPECT_EQ(0x0102, opt->getValue());
+
+    // Checks for address option
+    OptionPtr subopt = opt->getOption(D6O_IAADDR);
+    ASSERT_TRUE(subopt);
+    boost::shared_ptr<Option6IAAddr> addr(boost::dynamic_pointer_cast<Option6IAAddr>(subopt));
+    ASSERT_TRUE(addr);
+
+    EXPECT_EQ(D6O_IAADDR, addr->getType());
+    EXPECT_EQ(28, addr->len());
+    EXPECT_EQ(0x5000, addr->getPreferred());
+    EXPECT_EQ(0x7000, addr->getValid());
+    EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText());
+
+    // Checks for dummy option
+    subopt = opt->getOption(0xcafe);
+    ASSERT_TRUE(subopt); // should be non-NULL
+
+    EXPECT_EQ(0xcafe, subopt->getType());
+    EXPECT_EQ(4, subopt->len());
+    // There should be no data at all
+    EXPECT_EQ(0, subopt->getData().size());
+
+    // Try to get non-existent option.
+    subopt = opt->getOption(1);
+    // Expecting NULL which means that option does not exist.
+    ASSERT_FALSE(subopt);
+}
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
new file mode 100644
index 0000000..692bfa9
--- /dev/null
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -0,0 +1,609 @@
+// Copyright (C) 2012 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 <exceptions/exceptions.h>
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option6_addrlst.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp/option_definition.h>
+
+#include <gtest/gtest.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/pointer_cast.hpp>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::util;
+
+namespace {
+
+/// @brief OptionDefinition test class.
+///
+/// This class does not do anything useful but we keep
+/// it around for the future.
+class OptionDefinitionTest : public ::testing::Test {
+public:
+    // @brief Constructor.
+    OptionDefinitionTest() { }
+};
+
+TEST_F(OptionDefinitionTest, constructor) {
+    // Specify the option data type as string. This should get converted
+    // to enum value returned by getType().
+    OptionDefinition opt_def1("OPTION_CLIENTID", 1, "string");
+    EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
+    EXPECT_EQ(1, opt_def1.getCode());
+    EXPECT_EQ(OptionDefinition::STRING_TYPE,  opt_def1.getType());
+    EXPECT_FALSE(opt_def1.getArrayType());
+    EXPECT_NO_THROW(opt_def1.validate());
+
+    // Specify the option data type as an enum value.
+    OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
+                              OptionDefinition::EMPTY_TYPE);
+    EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
+    EXPECT_EQ(14, opt_def2.getCode());
+    EXPECT_EQ(OptionDefinition::EMPTY_TYPE, opt_def2.getType());
+    EXPECT_FALSE(opt_def2.getArrayType());
+    EXPECT_NO_THROW(opt_def1.validate());
+
+    // Check if it is possible to set that option is an array.
+    OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
+                              OptionDefinition::IPV6_ADDRESS_TYPE,
+                              true);
+    EXPECT_EQ("OPTION_NIS_SERVERS", opt_def3.getName());
+    EXPECT_EQ(27, opt_def3.getCode());
+    EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, opt_def3.getType());
+    EXPECT_TRUE(opt_def3.getArrayType());
+    EXPECT_NO_THROW(opt_def3.validate());
+
+    // The created object is invalid if invalid data type is specified but
+    // constructor shouldn't throw exception. The object is validated after
+    // it has been created.
+    EXPECT_NO_THROW(
+        OptionDefinition opt_def4("OPTION_SERVERID",
+                                  OptionDefinition::UNKNOWN_TYPE + 10,
+                                  OptionDefinition::STRING_TYPE);
+    );
+}
+
+TEST_F(OptionDefinitionTest, addRecordField) {
+    // We can only add fields to record if the option type has been
+    // specified as 'record'. We try all other types but 'record'
+    // here and expect exception to be thrown.
+    for (int i = 0; i < OptionDefinition::UNKNOWN_TYPE; ++i) {
+        // Do not try for 'record' type because this is the only
+        // type for which adding record will succeed.
+        if (i == OptionDefinition::RECORD_TYPE) {
+            continue;
+        }
+        OptionDefinition opt_def("OPTION_IAADDR", 5,
+                                 static_cast<OptionDefinition::DataType>(i));
+        EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
+    }
+
+    // Positive scenario starts here.
+    OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
+    EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
+    EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
+    // It should not matter if we specify field type by its name or using enum.
+    EXPECT_NO_THROW(opt_def.addRecordField(OptionDefinition::UINT32_TYPE));
+
+    // Check what we have actually added.
+    OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
+    ASSERT_EQ(3, fields.size());
+    EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, fields[0]);
+    EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[1]);
+    EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[2]);
+
+    // Let's try some more negative scenarios: use invalid data types.
+    EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
+    OptionDefinition::DataType invalid_type =
+        static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE + 10);
+    EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
+}
+
+TEST_F(OptionDefinitionTest, validate) {
+    // Not supported option type string is not allowed.
+    OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
+    EXPECT_THROW(opt_def1.validate(), isc::OutOfRange);
+
+    // Not supported option type enum value is not allowed.
+    OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OptionDefinition::UNKNOWN_TYPE);
+    EXPECT_THROW(opt_def2.validate(), isc::OutOfRange);
+
+    OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
+                              static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE
+                                                                      + 2));
+    EXPECT_THROW(opt_def3.validate(), isc::OutOfRange);
+    
+    // Empty option name is not allowed.
+    OptionDefinition opt_def4("", D6O_CLIENTID, "string");
+    EXPECT_THROW(opt_def4.validate(), isc::BadValue);
+
+    // Option name must not contain spaces.
+    OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
+    EXPECT_THROW(opt_def5.validate(), isc::BadValue);
+
+    OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string");
+    EXPECT_THROW(opt_def6.validate(), isc::BadValue);
+}
+
+TEST_F(OptionDefinitionTest, factoryAddrList6) {
+    OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
+                             "ipv6-address", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Create a list of some V6 addresses.
+    std::vector<asiolink::IOAddress> addrs;
+    addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
+    addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
+    addrs.push_back(asiolink::IOAddress("::1"));
+    addrs.push_back(asiolink::IOAddress("::2"));
+
+    // Write addresses to the buffer.
+    OptionBuffer buf;
+    for (int i = 0; i < addrs.size(); ++i) {
+        unsigned char* data = addrs[i].getAddress().to_v6().to_bytes().data();
+        // @todo Are there any sanity checks needed here on this raw pointer?
+        buf.insert(buf.end(), data, data + asiolink::V6ADDRESS_LEN);
+    }
+    // Create DHCPv6 option from this buffer. Once option is created it is
+    // supposed to have internal list of addresses that it parses out from
+    // the provided buffer.
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_NIS_SERVERS, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
+    boost::shared_ptr<Option6AddrLst> option_cast_v6 =
+        boost::static_pointer_cast<Option6AddrLst>(option_v6);
+    ASSERT_TRUE(option_cast_v6);
+    // Get the list of parsed addresses from the option object.
+    std::vector<asiolink::IOAddress> addrs_returned =
+        option_cast_v6->getAddresses();
+    // The list of addresses must exactly match addresses that we
+    // stored in the buffer to create the option from it.
+    EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
+
+    // The provided buffer's length must be a multiple of V6 address length.
+    // Let's extend the buffer by one byte so as this condition is not
+    // fulfilled anymore.
+    buf.insert(buf.end(), 1, 1);
+    // It should throw exception then.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_NIS_SERVERS, buf),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryAddrList4) {
+    OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
+                             "ipv4-address", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Create a list of some V6 addresses.
+    std::vector<asiolink::IOAddress> addrs;
+    addrs.push_back(asiolink::IOAddress("192.168.0.1"));
+    addrs.push_back(asiolink::IOAddress("172.16.1.1"));
+    addrs.push_back(asiolink::IOAddress("127.0.0.1"));
+    addrs.push_back(asiolink::IOAddress("213.41.23.12"));
+
+    // Write addresses to the buffer.
+    OptionBuffer buf;
+    for (int i = 0; i < addrs.size(); ++i) {
+        unsigned char* data = addrs[i].getAddress().to_v4().to_bytes().data();
+        // @todo Are there any sanity checks needed here on this raw pointer?
+        buf.insert(buf.end(), data, data + asiolink::V4ADDRESS_LEN);
+    }
+    // Create DHCPv6 option from this buffer. Once option is created it is
+    // supposed to have internal list of addresses that it parses out from
+    // the provided buffer.
+    OptionPtr option_v4;
+    ASSERT_NO_THROW(
+        option_v4 = factory(Option::V4, DHO_NAME_SERVERS, buf)
+    );
+    ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
+    // Get the list of parsed addresses from the option object.
+    boost::shared_ptr<Option4AddrLst> option_cast_v4 =
+        boost::static_pointer_cast<Option4AddrLst>(option_v4);
+    std::vector<asiolink::IOAddress> addrs_returned =
+        option_cast_v4->getAddresses();
+    // The list of addresses must exactly match addresses that we
+    // stored in the buffer to create the option from it.
+    EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
+
+    // The provided buffer's length must be a multiple of V4 address length.
+    // Let's extend the buffer by one byte so as this condition is not
+    // fulfilled anymore.
+    buf.insert(buf.end(), 1, 1);
+    // It should throw exception then.
+    EXPECT_THROW(factory(Option::V4, DHO_NIS_SERVERS, buf), isc::OutOfRange);
+}
+
+TEST_F(OptionDefinitionTest, factoryEmpty) {
+    OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Create option instance and provide empty buffer as expected.
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
+    // Expect 'empty' DHCPv6 option.
+    EXPECT_EQ(Option::V6, option_v6->getUniverse());
+    EXPECT_EQ(4, option_v6->getHeaderLen());
+    EXPECT_EQ(0, option_v6->getData().size());
+
+    // Repeat the same test scenario for DHCPv4 option.
+    EXPECT_THROW(factory(Option::V4, 214, OptionBuffer(2)),isc::BadValue);
+
+    OptionPtr option_v4;
+    ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, OptionBuffer()));
+    // Expect 'empty' DHCPv4 option.
+    EXPECT_EQ(Option::V4, option_v4->getUniverse());
+    EXPECT_EQ(2, option_v4->getHeaderLen());
+    EXPECT_EQ(0, option_v4->getData().size());
+
+    // This factory produces empty option (consisting of option type
+    // and length). Attempt to provide some data in the buffer should
+    // result in exception.
+    EXPECT_THROW(factory(Option::V6, D6O_RAPID_COMMIT,OptionBuffer(2)),isc::BadValue);
+}
+
+TEST_F(OptionDefinitionTest, factoryIA6) {
+    // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
+    const int option6_ia_len = 12;
+
+    // Get the factory function pointer.
+    OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", true);
+    // Each data field is uint32.
+    for (int i = 0; i < 3; ++i) {
+        EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
+    }
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Check the positive scenario.
+    OptionBuffer buf(12);
+    for (int i = 0; i < buf.size(); ++i) {
+        buf[i] = i;
+    }
+    OptionPtr option_v6;
+    ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IA_NA, buf));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IA));
+    boost::shared_ptr<Option6IA> option_cast_v6 =
+        boost::static_pointer_cast<Option6IA>(option_v6);
+    EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
+    EXPECT_EQ(0x04050607, option_cast_v6->getT1());
+    EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
+
+    // This should work for DHCPv6 only, try passing invalid universe value.
+    EXPECT_THROW(
+        factory(Option::V4, D6O_IA_NA, OptionBuffer(option6_ia_len)),
+        isc::BadValue
+    );
+    // The length of the buffer must be 12 bytes.
+    // Check too short buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
+        isc::OutOfRange
+     );
+    // Check too long buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len + 1)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryIAAddr6) {
+    // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
+    // valid-lifetime fields (each 4 bytes long).
+    const int option6_iaaddr_len = 24;
+
+    OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
+    ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
+    ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
+    ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    // Check the positive scenario.
+    OptionPtr option_v6;
+    asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
+    ASSERT_TRUE(addr_v6.getAddress().is_v6());
+    unsigned char* addr_bytes_v6 = addr_v6.getAddress().to_v6().to_bytes().data();
+    ASSERT_TRUE(addr_bytes_v6 != NULL);
+    OptionBuffer buf;
+    buf.insert(buf.end(), addr_bytes_v6, addr_bytes_v6 + asiolink::V6ADDRESS_LEN);
+    for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
+        buf.push_back(i);
+    }
+    //    ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IAADDR, buf));
+    try {
+        option_v6 = factory(Option::V6, D6O_IAADDR, buf);
+    } catch (const Exception& e) {
+        std::cout << e.what() << std::endl;
+    }
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
+    boost::shared_ptr<Option6IAAddr> option_cast_v6 =
+        boost::static_pointer_cast<Option6IAAddr>(option_v6);
+    EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
+    EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
+    EXPECT_EQ(0x04050607, option_cast_v6->getValid());
+
+    // This should work for DHCPv6 only, try passing invalid universe value.
+    EXPECT_THROW(
+        factory(Option::V4, D6O_IAADDR, OptionBuffer(option6_iaaddr_len)),
+        isc::BadValue
+    );
+    // The length of the buffer must be 12 bytes.
+    // Check too short buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
+        isc::OutOfRange
+     );
+    // Check too long buffer.
+    EXPECT_THROW(
+        factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len + 1)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
+    // The template function factoryInteger<> accepts integer values only
+    // as template typename. Here we try passing different type and
+    // see if it rejects it.
+    EXPECT_THROW(
+        OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, OptionBuffer(1)),
+        isc::dhcp::InvalidDataType
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryUint8) {
+    OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Try to use correct buffer length = 1 byte.
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+    // Validate the value.
+    boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+    EXPECT_EQ(1, option_cast_v6->getValue());
+
+    // Try to provide too large buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(3)),
+        isc::OutOfRange
+    );
+
+    // Try to provide zero-length buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
+        isc::OutOfRange
+    );
+
+    // @todo Add more cases for DHCPv4
+}
+
+TEST_F(OptionDefinitionTest, factoryUint16) {
+    OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Try to use correct buffer length = 2 bytes.
+    OptionBuffer buf;
+    buf.push_back(1);
+    buf.push_back(2);
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+    // Validate the value.
+    boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+    EXPECT_EQ(0x0102, option_cast_v6->getValue());
+
+    // Try to provide too large buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(3)),
+        isc::OutOfRange
+    );
+    // Try to provide zero-length buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
+        isc::OutOfRange
+    );
+
+    // @todo Add more cases for DHCPv4
+}
+
+TEST_F(OptionDefinitionTest, factoryUint32) {
+    OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    OptionBuffer buf;
+    buf.push_back(1);
+    buf.push_back(2);
+    buf.push_back(3);
+    buf.push_back(4);
+    ASSERT_NO_THROW(
+        option_v6 = factory(Option::V6, D6O_CLT_TIME, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+    // Validate the value.
+    boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+    EXPECT_EQ(0x01020304, option_cast_v6->getValue());
+
+    // Try to provide too large buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+    // Try to provide zero-length buffer. Expect exception.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
+        isc::OutOfRange
+    );
+
+    // @todo Add more cases for DHCPv4
+}
+
+TEST_F(OptionDefinitionTest, factoryUint16Array) {
+    // Let's define some dummy option.
+    const uint16_t opt_code = 79;
+    OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Positive scenario, initiate the buffer with length being
+    // multiple of uint16_t size.
+    // buffer elements will be: 0x112233.
+    OptionBuffer buf(6);
+    for (int i = 0; i < 6; ++i) {
+        buf[i] = i / 2;
+    }
+    // Constructor should succeed because buffer has correct size.
+    EXPECT_NO_THROW(
+        option_v6 = factory(Option::V6, opt_code, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
+    boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+    // Get the values from the initiated options and validate.
+    std::vector<uint16_t> values = option_cast_v6->getValues();
+    for (int i = 0; i < values.size(); ++i) {
+        // Expected value is calculated using on the same pattern
+        // as the one we used to initiate buffer:
+        // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
+        uint16_t expected = (i << 8) | i;
+        EXPECT_EQ(expected, values[i]);
+    }
+
+    // Provided buffer size must be greater than zero. Check if we
+    // get exception if we provide zero-length buffer.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
+        isc::OutOfRange
+    );
+    // Buffer length must be multiple of data type size.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, factoryUint32Array) {
+    // Let's define some dummy option.
+    const uint16_t opt_code = 80;
+
+    OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
+    Option::Factory* factory(NULL);
+    EXPECT_NO_THROW(factory = opt_def.getFactory());
+    ASSERT_TRUE(factory != NULL);
+
+    OptionPtr option_v6;
+    // Positive scenario, initiate the buffer with length being
+    // multiple of uint16_t size.
+    // buffer elements will be: 0x111122223333.
+    OptionBuffer buf(12);
+    for (int i = 0; i < buf.size(); ++i) {
+        buf[i] = i / 4;
+    }
+    // Constructor should succeed because buffer has correct size.
+    EXPECT_NO_THROW(
+        option_v6 = factory(Option::V6, opt_code, buf);
+    );
+    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
+    boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+    // Get the values from the initiated options and validate.
+    std::vector<uint32_t> values = option_cast_v6->getValues();
+    for (int i = 0; i < values.size(); ++i) {
+        // Expected value is calculated using on the same pattern
+        // as the one we used to initiate buffer:
+        // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
+        uint32_t expected = 0x01010101 * i;
+        EXPECT_EQ(expected, values[i]);
+    }
+
+    // Provided buffer size must be greater than zero. Check if we
+    // get exception if we provide zero-length buffer.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
+        isc::OutOfRange
+    );
+    // Buffer length must be multiple of data type size.
+    EXPECT_THROW(
+        option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+}
+
+TEST_F(OptionDefinitionTest, recognizeFormat) {
+    // IA_NA option format.
+    OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
+    for (int i = 0; i < 3; ++i) {
+        opt_def1.addRecordField("uint32");
+    }
+    EXPECT_TRUE(opt_def1.haveIA6Format());
+    // Create non-matching format to check that this function does not
+    // return 'true' all the time.
+    OptionDefinition opt_def2("OPTION_IA_NA", D6O_IA_NA, "uint16");
+    EXPECT_FALSE(opt_def2.haveIA6Format());
+
+    // IAADDR option format.
+    OptionDefinition opt_def3("OPTION_IAADDR", D6O_IAADDR, "record");
+    opt_def3.addRecordField("ipv6-address");
+    opt_def3.addRecordField("uint32");
+    opt_def3.addRecordField("uint32");
+    EXPECT_TRUE(opt_def3.haveIAAddr6Format());
+    // Create non-matching format to check that this function does not
+    // return 'true' all the time.
+    OptionDefinition opt_def4("OPTION_IAADDR", D6O_IAADDR, "uint32", true);
+    EXPECT_FALSE(opt_def4.haveIAAddr6Format());
+}
+
+} // anonymous namespace



More information about the bind10-changes mailing list