libkea_dhcpsrv_la_SOURCES += alloc_engine_log.cc alloc_engine_log.h
libkea_dhcpsrv_la_SOURCES += base_host_data_source.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
+libkea_dhcpsrv_la_SOURCES += cfg_4o6.h
libkea_dhcpsrv_la_SOURCES += cfg_db_access.cc cfg_db_access.h
libkea_dhcpsrv_la_SOURCES += cfg_duid.cc cfg_duid.h
libkea_dhcpsrv_la_SOURCES += cfg_hosts.cc cfg_hosts.h
--- /dev/null
+// Copyright (C) 2015 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 CFG_4OVER6_H
+#define CFG_4OVER6_H
+
+#include <string>
+#include <asiolink/io_address.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief This structure contains information about DHCP4o6 (RFC7341)
+///
+/// DHCP4o6 is completely optional. If it is not enabled, this structure
+/// does not contain any information.
+struct Cfg4o6 {
+
+ /// the default constructor.
+ ///
+ /// Initializes fields to their default value.
+ Cfg4o6()
+ :enabled_(false), subnet4o6_(std::make_pair(asiolink::IOAddress("::"), 128u)) {
+ }
+
+ /// @brief Returns whether the DHCP4o6 is enabled or not.
+ /// @return true if enabled
+ bool enabled() const {
+ return (enabled_);
+ }
+
+ /// @brief Sets the DHCP4o6 enabled status.
+ /// @param enabled specifies if the DHCP4o6 should be enabled or not
+ void enabled(bool enabled) {
+ enabled_ = enabled;
+ }
+
+ /// @brief Returns the DHCP4o6 interface.
+ /// @return value of the 4o6-interface parameter.
+ std::string getIface4o6() const {
+ return (iface4o6_);
+ }
+
+ /// @brief Sets the 4o6-interface.
+ /// @param iface name of the network interface the 4o6 traffic is received on
+ void setIface4o6(const std::string& iface) {
+ iface4o6_ = iface;
+ enabled_ = true;
+ }
+
+ /// @brief Returns prefix/len for the IPv6 subnet.
+ /// @return prefix/length pair
+ std::pair<asiolink::IOAddress, uint8_t> getSubnet4o6() const {
+ return (subnet4o6_);
+ }
+
+ /// @brief Sets the prefix/length information (content of the 4o6-subnet).
+ /// @param subnet IOAddress that represents a prefix
+ /// @param prefix specifies prefix length
+ void setSubnet4o6(const asiolink::IOAddress& subnet, uint8_t prefix) {
+ subnet4o6_ = std::make_pair(subnet, prefix);
+ enabled_ = true;
+ }
+
+ /// @brief Returns the interface-id.
+ /// @return the option representing interface-id (or NULL)
+ OptionPtr getInterfaceId() const {
+ return (interface_id_);
+ }
+
+ /// @brief Sets the interface-id
+ /// @param opt option to be used as interface-id match
+ void setInterfaceId(const OptionPtr& opt) {
+ interface_id_ = opt;
+ enabled_ = true;
+ }
+
+private:
+
+ /// Specifies if 4o6 is enabled on this subnet.
+ bool enabled_;
+
+ /// Specifies the network interface used as v4 subnet selector.
+ std::string iface4o6_;
+
+ /// Specifies the IPv6 subnet used for v4 subnet selection.
+ std::pair<asiolink::IOAddress, uint8_t> subnet4o6_;
+
+ /// Specifies the v6 interface-id used for v4 subnet selection.
+ OptionPtr interface_id_;
+};
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
+
+#endif
#include <dhcpsrv/cfg_subnets4.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/subnet_id.h>
+#include <dhcpsrv/addr_utilities.h>
+#include <asiolink/io_address.h>
#include <stats/stats_mgr.h>
using namespace isc::asiolink;
subnets_.push_back(subnet);
}
+Subnet4Ptr
+CfgSubnets4::selectSubnet4o6(const SubnetSelector& selector) const {
+
+ for (Subnet4Collection::const_iterator subnet = subnets_.begin();
+ subnet != subnets_.end(); ++subnet) {
+ Cfg4o6& cfg4o6 = (*subnet)->get4o6();
+
+ // Is this an 4o6 subnet at all?
+ if (!cfg4o6.enabled()) {
+ continue; // No? Let's try the next one.
+ }
+
+ // First match criteria: check if we have a prefix/len defined.
+ std::pair<asiolink::IOAddress, uint8_t> pref = cfg4o6.getSubnet4o6();
+ if (pref.first != IOAddress::IPV6_ZERO_ADDRESS()) {
+
+ // Let's check if the IPv6 address is in range
+ IOAddress first = firstAddrInPrefix(pref.first, pref.second);
+ IOAddress last = lastAddrInPrefix(pref.first, pref.second);
+ if ((first <= selector.remote_address_) &&
+ (selector.remote_address_ <= last)) {
+ return (*subnet);
+ }
+ }
+
+ // Second match criteria: check if the interface-id matches
+ if (cfg4o6.getInterfaceId() && selector.interface_id_ &&
+ cfg4o6.getInterfaceId()->equals(selector.interface_id_)) {
+ return (*subnet);
+ }
+
+ // Third match criteria: check if the interface name matches
+ if (!cfg4o6.getIface4o6().empty() && !selector.iface_name_.empty()
+ && cfg4o6.getIface4o6() == selector.iface_name_) {
+ return (*subnet);
+ }
+ }
+
+ // Ok, wasn't able to find any matching subnet.
+ return (Subnet4Ptr());
+}
+
Subnet4Ptr
CfgSubnets4::selectSubnet(const SubnetSelector& selector) const {
+
+ if (selector.dhcp4o6_) {
+ return selectSubnet4o6(selector);
+ }
+
// First use RAI link select sub-option or subnet select option
if (!selector.option_select_.isV4Zero()) {
return (selectSubnet(selector.option_select_,
/// @return true if the duplicate subnet exists.
bool isDuplicate(const Subnet4& subnet) const;
+ /// @brief Attempts to do subnet selection based on DHCP4o6 information
+ ///
+ /// The algorithm implemented is as follows:
+ ///
+ /// - First: try to match IPv6 subnet (4o6-subnet parameter) with the
+ /// remote IPv6 address of the incoming packet
+ /// - Second: try to match interface-id (4o6-interface-id parameter)
+ /// with the interface-id option in the incoming 4o6 packet
+ /// - Third: try to match interface-name (4o6-interface parameter)
+ /// with the name of the interface the incoming 4o6 packet was
+ /// received over.
+ ///
+ /// @todo: Add additional selection criteria. See
+ /// http://kea.isc.org/wiki/ISC-DHCP4o6-Design for details.
+ ///
+ /// @param selector
+ /// @return selected IPv4 subnet
+ Subnet4Ptr
+ selectSubnet4o6(const SubnetSelector& selector) const;
+
+
/// @brief A container for IPv4 subnets.
Subnet4Collection subnets_;
#include <dhcp/classify.h>
#include <dhcp/option_space_container.h>
#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/cfg_4o6.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/triplet.h>
#include <dhcpsrv/lease.h>
/// @brief A generic pointer to either Subnet4 or Subnet6 object
typedef boost::shared_ptr<Subnet> SubnetPtr;
-/// @brief This structure contains information about DHCP4o6 (RFC7341)
-///
-/// DHCP4o6 is completely optional. If it is not enabled, this structure
-/// does not contain any information.
-struct Cfg4o6 {
-
- /// the default constructor.
- ///
- /// Initializes fields to their default value.
- Cfg4o6()
- :enabled_(false), subnet4o6_(std::make_pair(asiolink::IOAddress("::"), 128u)) {
- }
-
- /// @brief Returns whether the DHCP4o6 is enabled or not.
- /// @return true if enabled
- bool enabled() const {
- return (enabled_);
- }
-
- /// @brief Sets the DHCP4o6 enabled status.
- /// @param enabled specifies if the DHCP4o6 should be enabled or not
- void enabled(bool enabled) {
- enabled_ = enabled;
- }
-
- /// @brief Returns the DHCP4o6 interface.
- /// @return value of the 4o6-interface parameter.
- std::string getIface4o6() const {
- return (iface4o6_);
- }
-
- /// @brief Sets the 4o6-interface.
- /// @param iface name of the network interface the 4o6 traffic is received on
- void setIface4o6(const std::string& iface) {
- iface4o6_ = iface;
- }
-
- /// @brief Returns prefix/len for the IPv6 subnet.
- /// @return prefix/length pair
- std::pair<asiolink::IOAddress, uint8_t> getSubnet4o6() const {
- return (subnet4o6_);
- }
-
- /// @brief Sets the prefix/length information (content of the 4o6-subnet).
- /// @param subnet IOAddress that represents a prefix
- /// @param prefix specifies prefix length
- void setSubnet4o6(const asiolink::IOAddress& subnet, uint8_t prefix) {
- subnet4o6_ = std::make_pair(subnet, prefix);
- }
-
- /// @brief Returns the interface-id.
- /// @return the option representing interface-id (or NULL)
- OptionPtr getInterfaceId() const {
- return (interface_id_);
- }
-
- /// @brief Sets the interface-id
- /// @param opt option to be used as interface-id match
- void setInterfaceId(const OptionPtr& opt) {
- interface_id_ = opt;
- }
-
-private:
-
- /// Specifies if 4o6 is enabled on this subnet.
- bool enabled_;
-
- /// Specifies the network interface used as v4 subnet selector.
- std::string iface4o6_;
-
- /// Specifies the IPv6 subnet used for v4 subnet selection.
- std::pair<asiolink::IOAddress, uint8_t> subnet4o6_;
-
- /// Specifies the v6 interface-id used for v4 subnet selection.
- OptionPtr interface_id_;
-};
/// @brief A configuration holder for IPv4 subnet.
///
/// @brief Name of the interface on which the message was received.
std::string iface_name_;
+ /// @brief Specifies if the packet is DHCP4o6
+ bool dhcp4o6_;
+
/// @brief Default constructor.
///
/// Sets the default values for the @c Selector.
first_relay_linkaddr_(asiolink::IOAddress("::")),
local_address_(asiolink::IOAddress("0.0.0.0")),
remote_address_(asiolink::IOAddress("0.0.0.0")),
- client_classes_(), iface_name_(std::string()) {
+ client_classes_(), iface_name_(std::string()),
+ dhcp4o6_(false) {
}
};
EXPECT_THROW(cfg.add(subnet3), isc::dhcp::DuplicateSubnetID);
}
+// This test checks if the IPv4 subnet can be selected based on the IPv6 address.
+TEST(CfgSubnets4Test, 4o6subnet) {
+ CfgSubnets4 cfg;
+
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3, 123));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3, 124));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3, 125));
+
+ subnet2->get4o6().setSubnet4o6(IOAddress("2001:db8:1::"), 48);
+ subnet3->get4o6().setSubnet4o6(IOAddress("2001:db8:2::"), 48);
+
+
+ cfg.add(subnet1);
+ cfg.add(subnet2);
+ cfg.add(subnet3);
+
+ SubnetSelector selector;
+ selector.dhcp4o6_ = true;
+ selector.remote_address_ = IOAddress("2001:db8:1::dead:beef");
+
+ EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
+}
+
} // end of anonymous namespace