#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_iaprefix.h>
#include <dhcp/option6_status_code.h>
+#include <dhcp/option6_pdexclude.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_vendor.h>
#include <dhcp/option_vendor_class.h>
(*l)->prefixlen_, (*l)->preferred_lft_,
(*l)->valid_lft_));
ia_rsp->addOption(addr);
+
+ // Client requests some options using ORO option. Try to
+ // get this option from client's message.
+ boost::shared_ptr<OptionIntArray<uint16_t> > option_oro =
+ boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >
+ (query->getOption(D6O_ORO));
+
+ if (option_oro) {
+
+ // Get the list of options that client requested.
+ const std::vector<uint16_t>& requested_opts = option_oro->getValues();
+
+ bool pdExcludeFound = false;
+
+ BOOST_FOREACH(uint16_t opt, requested_opts) {
+ if (opt == D6O_PD_EXCLUDE) {
+ pdExcludeFound = true;
+ break;
+ }
+ }
+
+ Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>
+ (ctx.subnet_->getPool(ctx.type_, (*l)->addr_, false));
+
+ if (pdExcludeFound && pool && pool->getPrefixExcludedLength() > 0) {
+ OptionPtr opt(new Option6PDExclude((*l)->addr_, (*l)->prefixlen_,
+ pool->getPrefixExcluded(), pool->getPrefixExcludedLength()));
+ addr->addOption(opt);
+ }
+ }
}
// It would be possible to insert status code=0(success) as well,
(*l)->addr_, (*l)->prefixlen_,
(*l)->preferred_lft_, (*l)->valid_lft_));
ia_rsp->addOption(prf);
+
+ // Client requests some options using ORO option. Try to
+ // get this option from client's message.
+ boost::shared_ptr<OptionIntArray<uint16_t> > option_oro =
+ boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >
+ (query->getOption(D6O_ORO));
+
+ if (option_oro) {
+
+ // Get the list of options that client requested.
+ const std::vector<uint16_t>& requested_opts = option_oro->getValues();
+
+ bool pdExcludeFound = false;
+
+ BOOST_FOREACH(uint16_t opt, requested_opts) {
+ if (opt == D6O_PD_EXCLUDE) {
+ pdExcludeFound = true;
+ break;
+ }
+ }
+
+ Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>
+ (ctx.subnet_->getPool(ctx.type_, (*l)->addr_, false));
+
+ if (pdExcludeFound && pool && pool->getPrefixExcludedLength() > 0) {
+ OptionPtr opt(new Option6PDExclude((*l)->addr_, (*l)->prefixlen_,
+ pool->getPrefixExcluded(), pool->getPrefixExcludedLength()));
+ prf->addOption(opt);
+ }
+ }
+
LOG_INFO(lease6_logger, DHCP6_PD_LEASE_RENEW)
.arg(query->getLabel())
.arg((*l)->addr_.toText())
BOOST_FOREACH(ConfigPair param, pd_pool_->mapValue()) {
std::string entry(param.first);
ParserPtr parser;
- if (entry == "prefix") {
+ if (entry == "prefix" || entry =="excluded-prefix") {
StringParserPtr str_parser(new StringParser(entry,
string_values_));
parser = str_parser;
- } else if (entry == "prefix-len" || entry == "delegated-len") {
+ } else if (entry == "prefix-len" || entry == "delegated-len" ||
+ entry == "excluded-prefix-len") {
Uint32ParserPtr code_parser(new Uint32Parser(entry,
uint32_values_));
parser = code_parser;
std::string addr_str = string_values_->getParam("prefix");
uint32_t prefix_len = uint32_values_->getParam("prefix-len");
uint32_t delegated_len = uint32_values_->getParam("delegated-len");
-
+ std::string excluded_prefix_str = "::";
+ uint32_t excluded_prefix_len = 0;
+ try {
+ excluded_prefix_str = string_values_->getParam("excluded-prefix");
+ excluded_prefix_len = uint32_values_->getParam("excluded-prefix-len");
+ } catch (DhcpConfigError& ex) {
+ }
// Attempt to construct the local pool.
- pool_.reset(new Pool6(Lease::TYPE_PD, IOAddress(addr_str),
- prefix_len, delegated_len));
+ pool_.reset(new Pool6(Lease::TYPE_PD, IOAddress(addr_str), prefix_len,
+ delegated_len, IOAddress(excluded_prefix_str),
+ excluded_prefix_len));
} catch (const std::exception& ex) {
// Some parameters don't exist or are invalid. Since we are not
// aware whether they don't exist or are invalid, let's append
libkea_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
libkea_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
libkea_dhcp___la_SOURCES += option6_iaprefix.cc option6_iaprefix.h
+libkea_dhcp___la_SOURCES += option6_pdexclude.cc option6_pdexclude.h
libkea_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
libkea_dhcp___la_SOURCES += option6_client_fqdn.cc option6_client_fqdn.h
libkea_dhcp___la_SOURCES += option6_status_code.cc option6_status_code.h
#define D6O_AFTR_NAME 64 /* RFC6334 */
#define D6O_ERP_LOCAL_DOMAIN_NAME 65 /* RFC6440 */
#define D6O_RSOO 66 /* RFC6422 */
-//#define D6O_PD_EXCLUDE 67 /* RFC6603 */
+#define D6O_PD_EXCLUDE 67 /* RFC6603 */
//#define D6O_VSS 68 /* RFC6607 */
//#define D6O_MIP6_IDINF 69 /* RFC6610 */
//#define D6O_MIP6_UDINF 70 /* RFC6610 */
--- /dev/null
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_pdexclude.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
+#include <boost/dynamic_bitset.hpp>
+
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <stdint.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+Option6PDExclude::Option6PDExclude(const isc::asiolink::IOAddress& addr,
+ uint8_t prefix_len,
+ const isc::asiolink::IOAddress& prefix_excluded,
+ uint8_t prefix_excluded_len
+ )
+ :Option(V6, D6O_PD_EXCLUDE)
+ ,addr_(addr), prefix_len_(prefix_len)
+ ,prefix_excluded_(prefix_excluded)
+ ,prefix_excluded_len_(prefix_excluded_len) {
+
+}
+
+void
+Option6PDExclude::pack(isc::util::OutputBuffer& buf) {
+ // Header = option code and length.
+ packHeader(buf);
+
+ uint8_t excludedPrefLenBytes = excludedPrefixLenBytes();
+
+ buf.writeData(&prefix_excluded_len_, sizeof(prefix_excluded_len_));
+
+ std::vector<uint8_t> addrV6 = prefix_excluded_.toBytes();
+ boost::dynamic_bitset<uint8_t> bits(addrV6.rbegin(), addrV6.rend());
+ bits = bits << prefix_len_;
+
+ for (int i = 0; i < excludedPrefLenBytes; i++) {
+ boost::dynamic_bitset<uint8_t> tmp = bits >> 120;
+
+ uint8_t val = static_cast<uint8_t>(tmp.to_ulong());
+
+ //Zero padded bits follow when prefix_excluded_len_ is not divided exactly by 8
+ if (i == excludedPrefLenBytes - 1) {
+ uint8_t excluded_prefix_bits_no = prefix_excluded_len_ - prefix_len_;
+
+ uint8_t unusedBits = 0xFF;
+ unusedBits <<= (8 - (excluded_prefix_bits_no % 8)) % 8;
+
+ val = val & unusedBits;
+ }
+ bits = bits << 8;
+ buf.writeData(&val, sizeof(val));
+ }
+}
+
+void Option6PDExclude::unpack(OptionBufferConstIter begin,
+ OptionBufferConstIter end) {
+ prefix_len_ = 0;
+ prefix_excluded_len_ = *begin;
+ begin += sizeof(uint8_t);
+ addr_ = IOAddress::IPV6_ZERO_ADDRESS();
+ prefix_excluded_ = IOAddress::IPV6_ZERO_ADDRESS();
+ begin = end;
+}
+
+uint16_t
+Option6PDExclude::len()
+{
+ return getHeaderLen() + sizeof (prefix_excluded_len_) +
+ excludedPrefixLenBytes();
+}
+
+uint8_t
+Option6PDExclude::excludedPrefixLenBytes()
+{
+ uint8_t excludedPrefLenBits = prefix_excluded_len_ - prefix_len_ - 1;
+ uint8_t excludedPrefLenBytes = (excludedPrefLenBits / 8) + 1;
+ return excludedPrefLenBytes;
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
--- /dev/null
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef OPTION6_PDEXCLUDE_H
+#define OPTION6_PDEXCLUDE_H
+
+#include <asiolink/io_address.h>
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief DHCPv6 Option class for handling list of IPv6 addresses.
+///
+/// This class handles a list of IPv6 addresses. An example of such option
+/// is dns-servers option. It can also be used to handle single address.
+class Option6PDExclude: public Option {
+
+public:
+
+ Option6PDExclude(const isc::asiolink::IOAddress& addr,
+ uint8_t prefix_len,
+ const isc::asiolink::IOAddress& prefix_excluded,
+ uint8_t prefix_excluded_len);
+
+ /// @brief Writes option in wire-format to a buffer.
+ ///
+ /// Writes option in wire-format to buffer, returns pointer to first unused
+ /// byte after stored option (that is useful for writing options one after
+ /// another).
+ ///
+ /// @param buf pointer to a buffer
+ ///
+ /// @throw BadValue Universe of the option is neither V4 nor V6.
+ virtual void pack(isc::util::OutputBuffer& buf);
+
+ /// @brief Parses received buffer.
+ ///
+ /// @param begin iterator to first byte of option data
+ /// @param end iterator to end of option data (first byte after option end)
+ virtual void unpack(OptionBufferConstIter begin,
+ OptionBufferConstIter end);
+
+ /// Returns length of the complete option (data length + DHCPv6
+ /// option header)
+ ///
+ /// @return length of the option
+ virtual uint16_t len();
+
+protected:
+ uint8_t excludedPrefixLenBytes();
+
+protected:
+ isc::asiolink::IOAddress addr_;
+ uint8_t prefix_len_;
+
+ isc::asiolink::IOAddress prefix_excluded_;
+ uint8_t prefix_excluded_len_;
+};
+
+/// @brief Pointer to the @c Option6PDExclude object.
+typedef boost::shared_ptr<Option6PDExclude> Option6PDExcludePtr;
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif // OPTION6_PDEXCLUDE_H
// that the validate() function in OptionDefinition object
// should have checked wheter it is a case for this option.
data_size = std::distance(data, data_buf.end());
+ } else if ( *field == OPT_IPV6_PREFIX_TYPE ) {
+ // The size of the IPV6 prefix type is determined as
+ // one byte (which is the size of the prefix in bits)
+ // followed by the prefix bits (right-padded with
+ // zeros to the nearest octet boundary)
+
+ uint8_t lenBits = *data;
+ uint8_t lenBytes = (lenBits + 7) / 8;
+ data_size = lenBytes + sizeof(lenBits);
} else {
// If we reached the end of buffer we assume that this option is
// truncated because there is no remaining data to initialize
data_types_["uint32"] = OPT_UINT32_TYPE;
data_types_["ipv4-address"] = OPT_IPV4_ADDRESS_TYPE;
data_types_["ipv6-address"] = OPT_IPV6_ADDRESS_TYPE;
+ data_types_["ipv6-prefix"] = OPT_IPV6_PREFIX_TYPE;
+ data_types_["psid"] = OPT_PSID_TYPE;
data_types_["string"] = OPT_STRING_TYPE;
data_types_["fqdn"] = OPT_FQDN_TYPE;
data_types_["record"] = OPT_RECORD_TYPE;
data_type_names_[OPT_UINT32_TYPE] = "uint32";
data_type_names_[OPT_IPV4_ADDRESS_TYPE] = "ipv4-address";
data_type_names_[OPT_IPV6_ADDRESS_TYPE] = "ipv6-address";
+ data_type_names_[OPT_IPV6_PREFIX_TYPE] = "ipv6-prefix";
+ data_type_names_[OPT_PSID_TYPE] = "psid";
data_type_names_[OPT_STRING_TYPE] = "string";
data_type_names_[OPT_FQDN_TYPE] = "fqdn";
data_type_names_[OPT_RECORD_TYPE] = "record";
case OPT_IPV6_ADDRESS_TYPE:
return (asiolink::V6ADDRESS_LEN);
+ case OPT_PSID_TYPE:
+ return (3);
+
default:
;
}
OPT_IPV4_ADDRESS_TYPE,
OPT_IPV6_ADDRESS_TYPE,
OPT_IPV6_PREFIX_TYPE,
+ OPT_PSID_TYPE,
OPT_STRING_TYPE,
OPT_FQDN_TYPE,
OPT_RECORD_TYPE,
return;
}
+ case OPT_PSID_TYPE:
+ {
+ std::string txt = value;
+
+ // first let's remove any whitespaces
+ boost::erase_all(txt, " "); // space
+ boost::erase_all(txt, "\t"); // tabulation
+
+ // Is this prefix/len notation?
+ size_t pos = txt.find("/");
+
+ if (pos == string::npos) {
+ isc_throw(BadDataTypeCast, "provided psid-len/psid "
+ << value
+ << " is not valid.");
+ }
+
+ std::string txt_psid = txt.substr(0, pos);
+ std::string txt_psid_len = txt.substr(pos + 1);
+
+ uint16_t psid = 0;
+ uint8_t psid_len = 0;
+
+ try {
+ psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
+ } catch (...) {
+ isc_throw(BadDataTypeCast, "provided psid "
+ << txt_psid
+ << " is not valid.");
+ }
+
+ try {
+ psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
+ } catch (...) {
+ isc_throw(BadDataTypeCast, "provided psid-len "
+ << txt_psid_len
+ << " is not valid.");
+ }
+
+ if (psid >= (1 << psid_len)) {
+ isc_throw(BadDataTypeCast, "provided psid "
+ << txt_psid
+ << " is not valid.");
+ }
+
+ if (psid_len > sizeof(uint16_t) * 8) {
+ isc_throw(BadDataTypeCast, "provided psid-len "
+ << txt_psid_len
+ << " is not valid.");
+ }
+
+ psid = psid << (sizeof(uint16_t) * 8 - psid_len);
+
+ // Write the psid length
+ OptionDataTypeUtil::writeInt<uint8_t>(psid_len, buf);
+
+ // Write the psid
+ OptionDataTypeUtil::writeInt<uint16_t>(psid, buf);
+
+ return;
+ }
case OPT_STRING_TYPE:
OptionDataTypeUtil::writeString(value, buf);
return;
// s46-v4v6bind
RECORD_DECL(S46_V4V6BIND, OPT_IPV4_ADDRESS_TYPE, OPT_IPV6_PREFIX_TYPE);
// s46-portparams
-RECORD_DECL(S46_PORTPARAMS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_UINT16_TYPE);
+RECORD_DECL(S46_PORTPARAMS, OPT_UINT8_TYPE, OPT_PSID_TYPE);
// status-code
RECORD_DECL(STATUS_CODE_RECORDS, OPT_UINT16_TYPE, OPT_STRING_TYPE);
// vendor-class
{ "erp-local-domain-name", D6O_ERP_LOCAL_DOMAIN_NAME, OPT_FQDN_TYPE, false,
NO_RECORD_DEF, "" },
{ "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "rsoo-opts" },
+ { "pd-exclude", D6O_PD_EXCLUDE, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
{ "client-linklayer-addr", D6O_CLIENT_LINKLAYER_ADDR, OPT_BINARY_TYPE, false,
NO_RECORD_DEF, "" },
{ "dhcpv4-message", D6O_DHCPV4_MSG, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
- :Pool(type, first, last), prefix_len_(128) {
+ :Pool(type, first, last), prefix_len_(128)
+ ,prefix_excluded_(isc::asiolink::IOAddress::IPV6_ZERO_ADDRESS())
+ ,prefix_excluded_len_(0) {
// check if specified address boundaries are sane
if (!first.isV6() || !last.isV6()) {
}
Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix,
- uint8_t prefix_len, uint8_t delegated_len /* = 128 */)
- :Pool(type, prefix, IOAddress("::")), prefix_len_(delegated_len) {
+ uint8_t prefix_len, uint8_t delegated_len /* = 128 */,
+ const isc::asiolink::IOAddress& prefix_excluded /*= IOAddress::IPV6_ZERO_ADDRESS()*/,
+ uint8_t prefix_excluded_len /* = 0 */)
+ :Pool(type, prefix, IOAddress("::")), prefix_len_(delegated_len)
+ , prefix_excluded_(prefix_excluded), prefix_excluded_len_(prefix_excluded_len){
// check if the prefix is sane
if (!prefix.isV6()) {
/// @param prefix_len specifies prefix length of the pool
/// @param delegated_len specifies lenght of the delegated prefixes
Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix,
- uint8_t prefix_len, uint8_t delegated_len = 128);
+ uint8_t prefix_len, uint8_t delegated_len = 128,
+ const isc::asiolink::IOAddress& prefix_excluded = isc::asiolink::IOAddress::IPV6_ZERO_ADDRESS(),
+ uint8_t prefix_excluded_len = 0);
/// @brief returns pool type
///
return (prefix_len_);
}
+ /// @brief returns excluded prefix
+ ///
+ /// This is useful for prefix definitions exclude pools.
+ /// @return excluded prefix
+ const isc::asiolink::IOAddress& getPrefixExcluded() const{
+ return (prefix_excluded_);
+ }
+
+ /// @brief returns excluded prefix length
+ ///
+ /// This is useful for prefix definitions exclude pools.
+ /// @return excluded prefix length (2-128)
+ uint8_t getPrefixExcludedLength() const{
+ return (prefix_excluded_len_);
+ }
+
/// @brief returns textual representation of the pool
///
/// @return textual representation
private:
/// @brief Defines prefix length (for TYPE_PD only)
uint8_t prefix_len_;
+
+ /// @brief The excluded prefix (for TYPE_PD only)
+ isc::asiolink::IOAddress prefix_excluded_;
+
+ /// @brief The excluded prefix length (for TYPE_PD only)
+ uint8_t prefix_excluded_len_;
};
/// @brief a pointer an IPv6 Pool