From: Stephen Morris Date: Wed, 7 Nov 2012 17:46:02 +0000 (+0000) Subject: [2414] Merge branch 'master' into trac2414 X-Git-Tag: trac2487_base~1^2~31^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa1643faad572dfc6c91d0fac707f4cac4d5b7a6;p=thirdparty%2Fkea.git [2414] Merge branch 'master' into trac2414 Conflicts: src/bin/dhcp6/dhcp6_messages.mes src/bin/dhcp6/dhcp6_srv.cc src/bin/dhcp6/dhcp6_srv.h src/bin/dhcp6/tests/dhcp6_srv_unittest.cc src/lib/dhcp/addr_utilities.cc src/lib/dhcp/tests/cfgmgr_unittest.cc Files automerged successfully: src/lib/dhcp/alloc_engine.cc src/lib/dhcp/subnet.h src/lib/dhcp/tests/alloc_engine_unittest.cc --- aa1643faad572dfc6c91d0fac707f4cac4d5b7a6 diff --cc src/bin/dhcp6/dhcp6_messages.mes index d5d3b721cb,aee34b5e23..5f9cd02b68 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@@ -141,18 -110,16 +141,28 @@@ This is a debug message issued during t It lists some information about the parameters with which the server is running. +% DHCP6_SUBNET_SELECTED the %1 subnet was selected for client assignment +This is a debug message informing that a given subnet was selected. It will +be used for address and option assignment. This is one of the early steps +in the processing of incoming client message. + +% DHCP6_SUBNET_SELECTION_FAILED failed to select a subnet for incoming packet, src=%1 type=%2 +This warning message is output when a packet was received from a subnet for +which the DHCPv6 server has not been configured. The cause is most likely due +to a misconfiguration of the server. The packet processing will continue, but +the response will only contain generic configuration parameters and no +addresses or prefixes. + + % DHCP6_NO_SUBNET_DEF_OPT failed to find subnet for address %1 when adding default options + This warning message indicates that when attempting to add default options to a response, + the server found that it was not configured to support the subnet from which the DHCPv6 + request was received. The packet has been ignored. + + % DHCP6_NO_SUBNET_REQ_OPT failed to find subnet for address %1 when adding requested options + This warning message indicates that when attempting to add requested options to a response, + the server found that it was not configured to support the subnet from which the DHCPv6 + request was received. The packet has been ignored. + % DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1 This critical error message indicates that the initial DHCPv6 configuration has failed. The server will start, but nothing will be diff --cc src/bin/dhcp6/dhcp6_srv.cc index ad3e1d70ff,946bccb52e..a7490359dd --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@@ -27,15 -31,9 +31,17 @@@ #include #include #include +#include +#include +#include +#include + +// @todo: Replace this with MySQL_LeaseMgr (or a LeaseMgr factory) +// once it is merged +#include + #include + using namespace isc; using namespace isc::asiolink; using namespace isc::dhcp; @@@ -49,26 -51,35 +55,29 @@@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port); - // First call to instance() will create IfaceMgr (it's a singleton) - // it may throw something if things go wrong + // Initialize objects required for DHCP server operation. try { - + // Initialize standard DHCPv6 option definitions. This function + // may throw bad_alloc if system goes out of memory during the + // creation if option definitions. It may also throw isc::Unexpected + // if definitions are wrong. This would mean error in implementation. + initStdOptionDefs(); - // Call IfaceMgr::instance() will create instance of Interface - // Manager (it's a singleton). It may throw if things go wrong. - if (IfaceMgr::instance().countIfaces() == 0) { - LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES); - shutdown_ = true; - return; + // Port 0 is used for testing purposes. It means that the server should + // not open any sockets at all. Some tests, e.g. configuration parser, + // require Dhcpv6Srv object, but they don't really need it to do + // anything. This speed up and simplifies the tests. + if (port > 0) { + if (IfaceMgr::instance().countIfaces() == 0) { + LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES); + shutdown_ = true; + return; + } - + IfaceMgr::instance().openSockets6(port); } - IfaceMgr::instance().openSockets6(port); - setServerID(); - /// @todo: instantiate LeaseMgr here once it is imlpemented. - } catch (const std::exception &e) { LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what()); shutdown_ = true; @@@ -300,188 -294,89 +309,233 @@@ void Dhcpv6Srv::copyDefaultOptions(cons // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST) } - void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) { - // TODO: question is currently unused, but we need it at least to know - // message type we are answering - - // Add server-id. + void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) { + // add server-id answer->addOption(getServerID()); - } + // Get the subnet object. It holds options to be sent to the client + // that belongs to the particular subnet. + Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr()); + // Warn if subnet is not supported and quit. + if (!subnet) { + LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_DEF_OPT) + .arg(question->getRemoteAddr().toText()); + return; + } + // Add DNS_SERVERS option. It should have been configured. + const Subnet::OptionContainer& options = subnet->getOptions(); + const Subnet::OptionContainerTypeIndex& idx = options.get<1>(); + const Subnet::OptionContainerTypeRange range = + idx.equal_range(D6O_NAME_SERVERS); + // In theory we may have multiple options with the same + // option code. They are not differentiated right now + // until support for option spaces is implemented. + // Until that's the case, simply add the first found option. + if (std::distance(range.first, range.second) > 0) { + answer->addOption(range.first->option); + } + } - void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) { - // TODO: question is currently unused, but we need to extract ORO from it - // and act on its content. Now we just send DNS-SERVERS option. + void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) { + // Get the subnet for a particular address. + Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr()); + if (!subnet) { + LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_REQ_OPT) + .arg(question->getRemoteAddr().toText()); + return; + } + // Add dns-servers option. + OptionPtr dnsservers(new Option6AddrLst(D6O_NAME_SERVERS, + IOAddress(HARDCODED_DNS_SERVER))); + answer->addOption(dnsservers); ++ + // Client requests some options using ORO option. Try to + // get this option from client's message. + boost::shared_ptr > option_oro = + boost::dynamic_pointer_cast >(question->getOption(D6O_ORO)); + // Option ORO not found. Don't do anything then. + if (!option_oro) { + return; + } + // Get the list of options that client requested. + const std::vector& requested_opts = option_oro->getValues(); + // Get the list of options configured for a subnet. + const Subnet::OptionContainer& options = subnet->getOptions(); + const Subnet::OptionContainerTypeIndex& idx = options.get<1>(); + // Try to match requested options with those configured for a subnet. + // If match is found, append configured option to the answer message. + BOOST_FOREACH(uint16_t opt, requested_opts) { + const Subnet::OptionContainerTypeRange& range = idx.equal_range(opt); + BOOST_FOREACH(Subnet::OptionDescriptor desc, range) { + answer->addOption(desc.option); + } + } } +OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) { + + // @todo: Implement Option6_StatusCode and rewrite this code here + vector data(text.c_str(), text.c_str() + text.length()); + data.insert(data.begin(), static_cast(code % 256)); + data.insert(data.begin(), static_cast(code >> 8)); + OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data)); + return (status); +} + +Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) { + Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr()); + + return (subnet); +} + void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) { - /// TODO Rewrite this once LeaseManager is implemented. - - // answer client's IA (this is mostly a dummy, - // so let's answer only first IA and hope there is only one) - boost::shared_ptr