mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[1651] Control interface in DHCPv4 refactored into separate class
- See ControlledDhcpv4Srv class for msgq support.
This commit is contained in:
@@ -20,11 +20,20 @@
|
|||||||
* @section dhcpv4Session BIND10 message queue integration
|
* @section dhcpv4Session BIND10 message queue integration
|
||||||
*
|
*
|
||||||
* DHCPv4 server component is now integrated with BIND10 message queue.
|
* DHCPv4 server component is now integrated with BIND10 message queue.
|
||||||
* The integration is performed by establish_session() and disconnect_session()
|
* The integration is performed by establishSession() and disconnectSession()
|
||||||
* functions in src/bin/dhcp4/main.cc file. isc::cc::Session cc_session
|
* functions in isc::dhcp::ControlledDhcpv4Srv class. main() method deifined
|
||||||
|
* in the src/bin/dhcp4/main.cc file instantiates isc::dhcp::ControlledDhcpv4Srv
|
||||||
|
* class that establishes connection with msgq and install necessary handlers
|
||||||
|
* for receiving commands and configuration updates. It is derived from
|
||||||
|
* a base isc::dhcp::Dhcpv4Srv class that implements DHCPv4 server functionality,
|
||||||
|
* without any controlling mechanisms.
|
||||||
|
*
|
||||||
|
* ControlledDhcpv4Srv instantiates several components to make management
|
||||||
|
* session possible. In particular, isc::cc::Session cc_session
|
||||||
* object uses ASIO for establishing connection. It registers its socket
|
* object uses ASIO for establishing connection. It registers its socket
|
||||||
* in isc::asiolink::IOService io_service object. Typically, other components that
|
* in isc::asiolink::IOService io_service object. Typically, other components
|
||||||
* use ASIO for their communication, register their other sockets in the
|
* (e.g. auth or resolver) that use ASIO for their communication, register their
|
||||||
|
* other sockets in the
|
||||||
* same io_service and then just call io_service.run() method that does
|
* same io_service and then just call io_service.run() method that does
|
||||||
* not return, until one of the callback decides that it is time to shut down
|
* not return, until one of the callback decides that it is time to shut down
|
||||||
* the whole component cal calls io_service.stop(). DHCPv4 works in a
|
* the whole component cal calls io_service.stop(). DHCPv4 works in a
|
||||||
@@ -43,7 +52,10 @@
|
|||||||
* be used with and without message queue. Second benefit is related to the
|
* be used with and without message queue. Second benefit is related to the
|
||||||
* first one: \ref libdhcp is supposed to be simple and robust and not require
|
* first one: \ref libdhcp is supposed to be simple and robust and not require
|
||||||
* many dependencies. One notable example of a use case that benefits from
|
* many dependencies. One notable example of a use case that benefits from
|
||||||
* this approach is a perfdhcp tool.
|
* this approach is a perfdhcp tool. Finally, the idea is that it should be
|
||||||
|
* possible to instantiate Dhcpv4Srv object directly, thus getting a server
|
||||||
|
* that does not support msgq. That is useful for embedded environments.
|
||||||
|
* It may also be useful in validation.
|
||||||
*
|
*
|
||||||
* @page dhcpv6 DHCPv6 Server Component
|
* @page dhcpv6 DHCPv6 Server Component
|
||||||
*
|
*
|
||||||
|
@@ -31,6 +31,7 @@ BUILT_SOURCES = spec_config.h
|
|||||||
pkglibexec_PROGRAMS = b10-dhcp4
|
pkglibexec_PROGRAMS = b10-dhcp4
|
||||||
|
|
||||||
b10_dhcp4_SOURCES = main.cc dhcp4_srv.cc dhcp4_srv.h
|
b10_dhcp4_SOURCES = main.cc dhcp4_srv.cc dhcp4_srv.h
|
||||||
|
b10_dhcp4_SOURCES += ctrl_dhcp4_srv.cc ctrl_dhcp4_srv.h
|
||||||
|
|
||||||
b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp++.la
|
b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp++.la
|
||||||
b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
|
b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
|
||||||
|
162
src/bin/dhcp4/ctrl_dhcp4_srv.cc
Normal file
162
src/bin/dhcp4/ctrl_dhcp4_srv.cc
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
// 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 <sys/types.h>
|
||||||
|
//#include <sys/socket.h>
|
||||||
|
//#include <sys/select.h>
|
||||||
|
//#include <netdb.h>
|
||||||
|
//#include <netinet/in.h>
|
||||||
|
//#include <stdlib.h>
|
||||||
|
//#include <errno.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <cc/session.h>
|
||||||
|
#include <cc/data.h>
|
||||||
|
|
||||||
|
#include <exceptions/exceptions.h>
|
||||||
|
#include <cc/session.h>
|
||||||
|
#include <config/ccsession.h>
|
||||||
|
|
||||||
|
#include <util/buffer.h>
|
||||||
|
#include <log/dummylog.h>
|
||||||
|
|
||||||
|
#include <dhcp4/spec_config.h>
|
||||||
|
#include <dhcp4/ctrl_dhcp4_srv.h>
|
||||||
|
#include <dhcp/iface_mgr.h>
|
||||||
|
|
||||||
|
#include <asiolink/asiolink.h>
|
||||||
|
#include <log/logger_support.h>
|
||||||
|
|
||||||
|
const char* const DHCP4_NAME = "b10-dhcp4";
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace isc::util;
|
||||||
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::util;
|
||||||
|
using namespace isc::data;
|
||||||
|
using namespace isc::cc;
|
||||||
|
using namespace isc::config;
|
||||||
|
using namespace isc::asiolink;
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace dhcp {
|
||||||
|
|
||||||
|
ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
|
||||||
|
|
||||||
|
ConstElementPtr
|
||||||
|
dhcp4_config_handler(ConstElementPtr new_config) {
|
||||||
|
cout << "b10-dhcp4: Received new config:" << new_config->str() << endl;
|
||||||
|
ConstElementPtr answer = isc::config::createAnswer(0,
|
||||||
|
"Thank you for sending config.");
|
||||||
|
return (answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstElementPtr
|
||||||
|
dhcp4_command_handler(const string& command, ConstElementPtr args) {
|
||||||
|
cout << "b10-dhcp4: Received new command: [" << command << "], args="
|
||||||
|
<< args->str() << endl;
|
||||||
|
if (command == "shutdown") {
|
||||||
|
if (ControlledDhcpv4Srv::server_) {
|
||||||
|
ControlledDhcpv4Srv::server_->shutdown();
|
||||||
|
}
|
||||||
|
ConstElementPtr answer = isc::config::createAnswer(0,
|
||||||
|
"Shutting down.");
|
||||||
|
return (answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstElementPtr answer = isc::config::createAnswer(1,
|
||||||
|
"Unrecognized command.");
|
||||||
|
|
||||||
|
return (answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlledDhcpv4Srv::sessionReader(void) {
|
||||||
|
// Process one asio event. If there are more events, iface_mgr will call
|
||||||
|
// this callback more than once.
|
||||||
|
if (server_) {
|
||||||
|
server_->io_service_.run_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlledDhcpv4Srv::establishSession() {
|
||||||
|
|
||||||
|
string specfile;
|
||||||
|
if (getenv("B10_FROM_BUILD")) {
|
||||||
|
specfile = string(getenv("B10_FROM_BUILD")) +
|
||||||
|
"/src/bin/auth/dhcp4.spec";
|
||||||
|
} else {
|
||||||
|
specfile = string(DHCP4_SPECFILE_LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @todo: Check if session is not established already. Throw, if it is.
|
||||||
|
|
||||||
|
cout << "b10-dhcp4: my specfile is " << specfile << endl;
|
||||||
|
|
||||||
|
cc_session_ = new Session(io_service_.get_io_service());
|
||||||
|
|
||||||
|
config_session_ = new ModuleCCSession(specfile, *cc_session_,
|
||||||
|
dhcp4_config_handler,
|
||||||
|
dhcp4_command_handler, false);
|
||||||
|
config_session_->start();
|
||||||
|
|
||||||
|
int ctrl_socket = cc_session_->getSocketDesc();
|
||||||
|
cout << "b10-dhcp4: Control session started, socket="
|
||||||
|
<< ctrl_socket << endl;
|
||||||
|
|
||||||
|
IfaceMgr::instance().set_session_socket(ctrl_socket, sessionReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlledDhcpv4Srv::disconnectSession() {
|
||||||
|
if (config_session_) {
|
||||||
|
delete config_session_;
|
||||||
|
config_session_ = NULL;
|
||||||
|
}
|
||||||
|
if (cc_session_) {
|
||||||
|
cc_session_->disconnect();
|
||||||
|
delete cc_session_;
|
||||||
|
cc_session_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/,
|
||||||
|
bool verbose /* false */)
|
||||||
|
:Dhcpv4Srv(port), cc_session_(NULL), config_session_(NULL) {
|
||||||
|
|
||||||
|
// Initialize logging. If verbose, we'll use maximum verbosity.
|
||||||
|
isc::log::initLogger(DHCP4_NAME,
|
||||||
|
(verbose ? isc::log::DEBUG : isc::log::INFO),
|
||||||
|
isc::log::MAX_DEBUG_LEVEL, NULL);
|
||||||
|
server_ = this; // remember this instance for use in callback
|
||||||
|
|
||||||
|
establishSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlledDhcpv4Srv::shutdown() {
|
||||||
|
io_service_.stop(); // Stop ASIO transmissions
|
||||||
|
Dhcpv4Srv::shutdown(); // Initiate DHCPv4 shutdown procedure.
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
|
||||||
|
disconnectSession();
|
||||||
|
|
||||||
|
server_ = NULL; // forget this instance. There should be no callback anymore
|
||||||
|
// at this stage anyway.
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
85
src/bin/dhcp4/ctrl_dhcp4_srv.h
Normal file
85
src/bin/dhcp4/ctrl_dhcp4_srv.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// 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 CTRL_DHCPV4_SRV_H
|
||||||
|
#define CTRL_DHCPV4_SRV_H
|
||||||
|
|
||||||
|
#include <dhcp4/dhcp4_srv.h>
|
||||||
|
#include <asiolink/asiolink.h>
|
||||||
|
#include <cc/session.h>
|
||||||
|
#include <config/ccsession.h>
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace dhcp {
|
||||||
|
|
||||||
|
/// @brief Controlled version of the DHCPv4 server
|
||||||
|
///
|
||||||
|
/// This is a class that is responsible for establishing connection
|
||||||
|
/// with msqg (receving commands and configuration). This is an extended
|
||||||
|
/// version of Dhcpv4Srv class that is purely a DHCPv4 server, without
|
||||||
|
/// external control. ControlledDhcpv4Srv should be used in typical BIND10
|
||||||
|
/// (i.e. featuring msgq) environment, while Dhcpv4Srv should be used in
|
||||||
|
/// embedded environments.
|
||||||
|
///
|
||||||
|
/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
|
||||||
|
/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
|
||||||
|
class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
|
||||||
|
public:
|
||||||
|
ControlledDhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT,
|
||||||
|
bool verbose = false);
|
||||||
|
|
||||||
|
/// @brief Establishes msgq session.
|
||||||
|
///
|
||||||
|
/// Creates session that will be used to receive commands and updated
|
||||||
|
/// configuration from boss (or indirectly from user via bindctl).
|
||||||
|
void establishSession();
|
||||||
|
|
||||||
|
/// @brief Terminates existing session.
|
||||||
|
///
|
||||||
|
/// This method terminates existing session with msgq. After calling
|
||||||
|
/// it, not further messages over msgq (commands or configuration updates)
|
||||||
|
/// may be received.
|
||||||
|
///
|
||||||
|
/// It is ok to call this method when session is disconnected already.
|
||||||
|
void disconnectSession();
|
||||||
|
|
||||||
|
/// @brief Initiates shutdown procedure for the whole DHCPv4 server.
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
~ControlledDhcpv4Srv();
|
||||||
|
|
||||||
|
static ControlledDhcpv4Srv* server_;
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/// @brief callback that will be called from iface_mgr when command/config arrives
|
||||||
|
///
|
||||||
|
/// This static callback method is called from IfaceMgr::receive4() method,
|
||||||
|
/// when there is a new command or configuration sent over msgq.
|
||||||
|
static void sessionReader(void);
|
||||||
|
|
||||||
|
/// @brief IOService object, used for all ASIO operations
|
||||||
|
isc::asiolink::IOService io_service_;
|
||||||
|
|
||||||
|
/// @brief Helper session object that represents raw connection to msgq
|
||||||
|
isc::cc::Session* cc_session_;
|
||||||
|
|
||||||
|
/// @brief Session that receives configuation and commands
|
||||||
|
isc::config::ModuleCCSession* config_session_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace isc::dhcp
|
||||||
|
}; // namespace isc
|
||||||
|
|
||||||
|
#endif
|
@@ -32,6 +32,13 @@ namespace dhcp {
|
|||||||
/// that is going to be used as server-identifier, receives incoming
|
/// that is going to be used as server-identifier, receives incoming
|
||||||
/// packets, processes them, manages leases assignment and generates
|
/// packets, processes them, manages leases assignment and generates
|
||||||
/// appropriate responses.
|
/// appropriate responses.
|
||||||
|
///
|
||||||
|
/// This class does not support any controlling mechanisms directly.
|
||||||
|
/// See derived \ref ControlledDhcv4Srv class for support for
|
||||||
|
/// command and configuration updates over msgq.
|
||||||
|
///
|
||||||
|
/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
|
||||||
|
/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
|
||||||
class Dhcpv4Srv : public boost::noncopyable {
|
class Dhcpv4Srv : public boost::noncopyable {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -60,7 +67,7 @@ class Dhcpv4Srv : public boost::noncopyable {
|
|||||||
/// critical error.
|
/// critical error.
|
||||||
bool run();
|
bool run();
|
||||||
|
|
||||||
/// @brief instructs server to shut down.
|
/// @brief Instructs the server to shut down.
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2009-2011 Internet Systems Consortium, Inc. ("ISC")
|
// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -13,50 +13,26 @@
|
|||||||
// PERFORMANCE OF THIS SOFTWARE.
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <cc/session.h>
|
|
||||||
#include <cc/data.h>
|
|
||||||
|
|
||||||
#include <exceptions/exceptions.h>
|
#include <exceptions/exceptions.h>
|
||||||
#include <cc/session.h>
|
|
||||||
#include <config/ccsession.h>
|
|
||||||
|
|
||||||
#include <util/buffer.h>
|
|
||||||
#include <log/dummylog.h>
|
#include <log/dummylog.h>
|
||||||
|
#include <dhcp4/ctrl_dhcp4_srv.h>
|
||||||
#include <dhcp4/spec_config.h>
|
|
||||||
#include <dhcp4/dhcp4_srv.h>
|
|
||||||
#include <dhcp/iface_mgr.h>
|
#include <dhcp/iface_mgr.h>
|
||||||
|
|
||||||
#include <asiolink/asiolink.h>
|
|
||||||
#include <log/logger_support.h>
|
|
||||||
|
|
||||||
const char* const DHCP4_NAME = "b10-dhcp4";
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace isc::util;
|
|
||||||
using namespace isc::dhcp;
|
using namespace isc::dhcp;
|
||||||
using namespace isc::util;
|
|
||||||
using namespace isc::data;
|
/// This file contains entry point (main() function) for standard DHCPv4 server
|
||||||
using namespace isc::cc;
|
/// component for BIND10 framework. It parses command-line arguments and
|
||||||
using namespace isc::config;
|
/// instantiates ControlledDhcpv4Srv class that is responsible for establishing
|
||||||
using namespace isc::asiolink;
|
/// connection with msgq (receiving commands and configuration) and also
|
||||||
|
/// creating Dhcpv4 server object as well.
|
||||||
|
///
|
||||||
|
/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
|
||||||
|
/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool verbose_mode = false;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
usage() {
|
usage() {
|
||||||
cerr << "Usage: b10-dhcp4 [-v]"
|
cerr << "Usage: b10-dhcp4 [-v]"
|
||||||
@@ -66,102 +42,10 @@ usage() {
|
|||||||
}
|
}
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
|
||||||
/// @brief DHCPv4 context (provides access to essential objects)
|
|
||||||
///
|
|
||||||
/// This is a structure that provides access to essential objects
|
|
||||||
/// used during DHCPv4 operation: Dhcpv4Srv object itself and
|
|
||||||
/// also objects required for msgq session management.
|
|
||||||
struct DHCPv4Context {
|
|
||||||
IOService io_service;
|
|
||||||
Session* cc_session;
|
|
||||||
ModuleCCSession* config_session;
|
|
||||||
Dhcpv4Srv* server;
|
|
||||||
DHCPv4Context(): cc_session(NULL), config_session(NULL), server(NULL) { };
|
|
||||||
};
|
|
||||||
|
|
||||||
DHCPv4Context dhcp4;
|
|
||||||
|
|
||||||
// Global objects are ugly, but that is the most convenient way of
|
|
||||||
// having it accessible from handlers.
|
|
||||||
|
|
||||||
// The same applies to global pointers. Ugly, but useful.
|
|
||||||
|
|
||||||
ConstElementPtr
|
|
||||||
dhcp4_config_handler(ConstElementPtr new_config) {
|
|
||||||
cout << "b10-dhcp4: Received new config:" << new_config->str() << endl;
|
|
||||||
ConstElementPtr answer = isc::config::createAnswer(0,
|
|
||||||
"Thank you for sending config.");
|
|
||||||
return (answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstElementPtr
|
|
||||||
dhcp4_command_handler(const string& command, ConstElementPtr args) {
|
|
||||||
cout << "b10-dhcp4: Received new command: [" << command << "], args="
|
|
||||||
<< args->str() << endl;
|
|
||||||
if (command == "shutdown") {
|
|
||||||
if (dhcp4.server) {
|
|
||||||
dhcp4.server->shutdown();
|
|
||||||
}
|
|
||||||
dhcp4.io_service.stop();
|
|
||||||
ConstElementPtr answer = isc::config::createAnswer(0,
|
|
||||||
"Shutting down.");
|
|
||||||
return (answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstElementPtr answer = isc::config::createAnswer(1,
|
|
||||||
"Unrecognized command.");
|
|
||||||
|
|
||||||
return (answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief callback that will be called from iface_mgr when command/config arrives
|
|
||||||
void session_reader(void) {
|
|
||||||
// Process one asio event. If there are more events, iface_mgr will call
|
|
||||||
// this callback more than once.
|
|
||||||
dhcp4.io_service.run_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Establishes msgq session.
|
|
||||||
///
|
|
||||||
/// Creates session that will be used to receive commands and updated
|
|
||||||
/// configuration from boss (or indirectly from user via bindctl).
|
|
||||||
void establish_session() {
|
|
||||||
|
|
||||||
string specfile;
|
|
||||||
if (getenv("B10_FROM_BUILD")) {
|
|
||||||
specfile = string(getenv("B10_FROM_BUILD")) +
|
|
||||||
"/src/bin/auth/dhcp4.spec";
|
|
||||||
} else {
|
|
||||||
specfile = string(DHCP4_SPECFILE_LOCATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "b10-dhcp4: my specfile is " << specfile << endl;
|
|
||||||
|
|
||||||
dhcp4.cc_session = new Session(dhcp4.io_service.get_io_service());
|
|
||||||
|
|
||||||
dhcp4.config_session = new ModuleCCSession(specfile, *dhcp4.cc_session,
|
|
||||||
dhcp4_config_handler,
|
|
||||||
dhcp4_command_handler, false);
|
|
||||||
dhcp4.config_session->start();
|
|
||||||
|
|
||||||
int ctrl_socket = dhcp4.cc_session->getSocketDesc();
|
|
||||||
cout << "b10-dhcp4: Control session started, socket="
|
|
||||||
<< ctrl_socket << endl;
|
|
||||||
|
|
||||||
IfaceMgr::instance().set_session_socket(ctrl_socket, session_reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disconnect_session() {
|
|
||||||
dhcp4.cc_session->disconnect();
|
|
||||||
delete dhcp4.config_session;
|
|
||||||
dhcp4.config_session = NULL;
|
|
||||||
delete dhcp4.cc_session;
|
|
||||||
dhcp4.cc_session = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[]) {
|
main(int argc, char* argv[]) {
|
||||||
int ch;
|
int ch;
|
||||||
|
bool verbose_mode = false; // should server be verbose?
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, ":v")) != -1) {
|
while ((ch = getopt(argc, argv, ":v")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
@@ -175,11 +59,6 @@ main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize logging. If verbose, we'll use maximum verbosity.
|
|
||||||
isc::log::initLogger(DHCP4_NAME,
|
|
||||||
(verbose_mode ? isc::log::DEBUG : isc::log::INFO),
|
|
||||||
isc::log::MAX_DEBUG_LEVEL, NULL);
|
|
||||||
|
|
||||||
cout << "b10-dhcp4: My pid is " << getpid() << endl;
|
cout << "b10-dhcp4: My pid is " << getpid() << endl;
|
||||||
|
|
||||||
if (argc - optind > 0) {
|
if (argc - optind > 0) {
|
||||||
@@ -187,19 +66,17 @@ main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
ControlledDhcpv4Srv* server = NULL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
establish_session();
|
|
||||||
|
|
||||||
cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
|
cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
|
||||||
dhcp4.server = new Dhcpv4Srv();
|
|
||||||
dhcp4.server->run();
|
|
||||||
|
|
||||||
disconnect_session();
|
server = new ControlledDhcpv4Srv(DHCP4_SERVER_PORT, verbose_mode);
|
||||||
|
server->run();
|
||||||
|
delete server;
|
||||||
|
|
||||||
delete dhcp4.server;
|
server = NULL;
|
||||||
dhcp4.server = NULL;
|
|
||||||
|
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;
|
cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;
|
||||||
|
274
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
Normal file
274
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
// Copyright (C) 2011 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 <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <dhcp/dhcp4.h>
|
||||||
|
#include <dhcp4/dhcp4_srv.h>
|
||||||
|
#include <dhcp/option.h>
|
||||||
|
#include <asiolink/io_address.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace isc;
|
||||||
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::asiolink;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char* const INTERFACE_FILE = "interfaces.txt";
|
||||||
|
|
||||||
|
class NakedDhcpv4Srv: public Dhcpv4Srv {
|
||||||
|
// "naked" DHCPv4 server, exposes internal fields
|
||||||
|
public:
|
||||||
|
NakedDhcpv4Srv():Dhcpv4Srv(DHCP4_SERVER_PORT + 10000) { }
|
||||||
|
|
||||||
|
boost::shared_ptr<Pkt4> processDiscover(boost::shared_ptr<Pkt4>& discover) {
|
||||||
|
return Dhcpv4Srv::processDiscover(discover);
|
||||||
|
}
|
||||||
|
boost::shared_ptr<Pkt4> processRequest(boost::shared_ptr<Pkt4>& request) {
|
||||||
|
return Dhcpv4Srv::processRequest(request);
|
||||||
|
}
|
||||||
|
void processRelease(boost::shared_ptr<Pkt4>& release) {
|
||||||
|
return Dhcpv4Srv::processRelease(release);
|
||||||
|
}
|
||||||
|
void processDecline(boost::shared_ptr<Pkt4>& decline) {
|
||||||
|
Dhcpv4Srv::processDecline(decline);
|
||||||
|
}
|
||||||
|
boost::shared_ptr<Pkt4> processInform(boost::shared_ptr<Pkt4>& inform) {
|
||||||
|
return Dhcpv4Srv::processInform(inform);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Dhcpv4SrvTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
Dhcpv4SrvTest() {
|
||||||
|
unlink(INTERFACE_FILE);
|
||||||
|
fstream fakeifaces(INTERFACE_FILE, ios::out | ios::trunc);
|
||||||
|
if (if_nametoindex("lo") > 0) {
|
||||||
|
fakeifaces << "lo 127.0.0.1";
|
||||||
|
} else if (if_nametoindex("lo0") > 0) {
|
||||||
|
fakeifaces << "lo0 127.0.0.1";
|
||||||
|
}
|
||||||
|
fakeifaces.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageCheck(const boost::shared_ptr<Pkt4>& q,
|
||||||
|
const boost::shared_ptr<Pkt4>& a) {
|
||||||
|
ASSERT_TRUE(q);
|
||||||
|
ASSERT_TRUE(a);
|
||||||
|
|
||||||
|
EXPECT_EQ(q->getHops(), a->getHops());
|
||||||
|
EXPECT_EQ(q->getIface(), a->getIface());
|
||||||
|
EXPECT_EQ(q->getIndex(), a->getIndex());
|
||||||
|
EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
|
||||||
|
|
||||||
|
// check that bare minimum of required options are there
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_ROUTERS));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_DHCP_LEASE_TIME));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_ROUTERS));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME));
|
||||||
|
EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME_SERVERS));
|
||||||
|
|
||||||
|
// check that something is offered
|
||||||
|
EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
~Dhcpv4SrvTest() {
|
||||||
|
unlink(INTERFACE_FILE);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(Dhcpv4SrvTest, basic) {
|
||||||
|
// nothing to test. DHCPv4_srv instance is created
|
||||||
|
// in test fixture. It is destroyed in destructor
|
||||||
|
|
||||||
|
Dhcpv4Srv* srv = NULL;
|
||||||
|
ASSERT_NO_THROW({
|
||||||
|
srv = new Dhcpv4Srv(DHCP4_SERVER_PORT + 10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
delete srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Dhcpv4SrvTest, processDiscover) {
|
||||||
|
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
|
||||||
|
vector<uint8_t> mac(6);
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
mac[i] = 255 - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDISCOVER, 1234));
|
||||||
|
boost::shared_ptr<Pkt4> offer;
|
||||||
|
|
||||||
|
pkt->setIface("eth0");
|
||||||
|
pkt->setIndex(17);
|
||||||
|
pkt->setHWAddr(1, 6, mac);
|
||||||
|
pkt->setRemoteAddr(IOAddress("192.0.2.56"));
|
||||||
|
pkt->setGiaddr(IOAddress("192.0.2.67"));
|
||||||
|
|
||||||
|
// let's make it a relayed message
|
||||||
|
pkt->setHops(3);
|
||||||
|
pkt->setRemotePort(DHCP4_SERVER_PORT);
|
||||||
|
|
||||||
|
// should not throw
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
offer = srv->processDiscover(pkt);
|
||||||
|
);
|
||||||
|
|
||||||
|
// should return something
|
||||||
|
ASSERT_TRUE(offer);
|
||||||
|
|
||||||
|
EXPECT_EQ(DHCPOFFER, offer->getType());
|
||||||
|
|
||||||
|
// this is relayed message. It should be sent back to relay address.
|
||||||
|
EXPECT_EQ(pkt->getGiaddr(), offer->getRemoteAddr());
|
||||||
|
|
||||||
|
MessageCheck(pkt, offer);
|
||||||
|
|
||||||
|
// now repeat the test for directly sent message
|
||||||
|
pkt->setHops(0);
|
||||||
|
pkt->setGiaddr(IOAddress("0.0.0.0"));
|
||||||
|
pkt->setRemotePort(DHCP4_CLIENT_PORT);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
offer = srv->processDiscover(pkt);
|
||||||
|
);
|
||||||
|
|
||||||
|
// should return something
|
||||||
|
ASSERT_TRUE(offer);
|
||||||
|
|
||||||
|
EXPECT_EQ(DHCPOFFER, offer->getType());
|
||||||
|
|
||||||
|
// this is direct message. It should be sent back to origin, not
|
||||||
|
// to relay.
|
||||||
|
EXPECT_EQ(pkt->getRemoteAddr(), offer->getRemoteAddr());
|
||||||
|
|
||||||
|
MessageCheck(pkt, offer);
|
||||||
|
|
||||||
|
delete srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Dhcpv4SrvTest, processRequest) {
|
||||||
|
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
|
||||||
|
vector<uint8_t> mac(6);
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
mac[i] = i*10;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<Pkt4> req(new Pkt4(DHCPREQUEST, 1234));
|
||||||
|
boost::shared_ptr<Pkt4> ack;
|
||||||
|
|
||||||
|
req->setIface("eth0");
|
||||||
|
req->setIndex(17);
|
||||||
|
req->setHWAddr(1, 6, mac);
|
||||||
|
req->setRemoteAddr(IOAddress("192.0.2.56"));
|
||||||
|
req->setGiaddr(IOAddress("192.0.2.67"));
|
||||||
|
|
||||||
|
// should not throw
|
||||||
|
ASSERT_NO_THROW(
|
||||||
|
ack = srv->processRequest(req);
|
||||||
|
);
|
||||||
|
|
||||||
|
// should return something
|
||||||
|
ASSERT_TRUE(ack);
|
||||||
|
|
||||||
|
EXPECT_EQ(DHCPACK, ack->getType());
|
||||||
|
|
||||||
|
// this is relayed message. It should be sent back to relay address.
|
||||||
|
EXPECT_EQ(req->getGiaddr(), ack->getRemoteAddr());
|
||||||
|
|
||||||
|
MessageCheck(req, ack);
|
||||||
|
|
||||||
|
// now repeat the test for directly sent message
|
||||||
|
req->setHops(0);
|
||||||
|
req->setGiaddr(IOAddress("0.0.0.0"));
|
||||||
|
req->setRemotePort(DHCP4_CLIENT_PORT);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
ack = srv->processDiscover(req);
|
||||||
|
);
|
||||||
|
|
||||||
|
// should return something
|
||||||
|
ASSERT_TRUE(ack);
|
||||||
|
|
||||||
|
EXPECT_EQ(DHCPOFFER, ack->getType());
|
||||||
|
|
||||||
|
// this is direct message. It should be sent back to origin, not
|
||||||
|
// to relay.
|
||||||
|
EXPECT_EQ(ack->getRemoteAddr(), req->getRemoteAddr());
|
||||||
|
|
||||||
|
MessageCheck(req, ack);
|
||||||
|
|
||||||
|
delete srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Dhcpv4SrvTest, processRelease) {
|
||||||
|
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
|
||||||
|
|
||||||
|
boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPRELEASE, 1234));
|
||||||
|
|
||||||
|
// should not throw
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
srv->processRelease(pkt);
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: Implement more reasonable tests before starting
|
||||||
|
// work on processSomething() method.
|
||||||
|
|
||||||
|
delete srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Dhcpv4SrvTest, processDecline) {
|
||||||
|
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
|
||||||
|
|
||||||
|
boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDECLINE, 1234));
|
||||||
|
|
||||||
|
// should not throw
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
srv->processDecline(pkt);
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: Implement more reasonable tests before starting
|
||||||
|
// work on processSomething() method.
|
||||||
|
delete srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Dhcpv4SrvTest, processInform) {
|
||||||
|
NakedDhcpv4Srv* srv = new NakedDhcpv4Srv();
|
||||||
|
|
||||||
|
boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPINFORM, 1234));
|
||||||
|
|
||||||
|
// should not throw
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
srv->processInform(pkt);
|
||||||
|
);
|
||||||
|
|
||||||
|
// should return something
|
||||||
|
EXPECT_TRUE(srv->processInform(pkt));
|
||||||
|
|
||||||
|
// TODO: Implement more reasonable tests before starting
|
||||||
|
// work on processSomething() method.
|
||||||
|
|
||||||
|
delete srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
Reference in New Issue
Block a user