This section is targeted for developers only. Network administrators do not need to read this section in order to use DHCP Cluster at its full potential. Curious techies and developers will find below details of how the server works and how to extend it.
DHCP Cluster makes a clear distinction between cold data (slowly changing) and hot data (real time).
Cold data is manually edited by the network administrator and contains global DHCP parameters, network topology and detailed options lists to be sent back to the clients. Cold data is stored in an XML file or in the backend database.
Hot data is automatically constructed in real time from client requests and server responses. It contains basically IP leases: addresses distributed to clients. Since it is critical that a specific IP address cannot be given to two different clients, this information is updated in real time by each node in the cluster. Hot data is always stored in the central database.
Isolating Cold data from Hot data allows some very aggressive optimisations. Hot data remains centrally stored in the database and is accessed in real-time. On the opposite, Cold data is cached in each front-end for maximum performance. The front-end checks periodically (every x minutes) to check whether the configurations has changed. Front-ends should reload most of its configuration on the fly without a server restart - especially network topology changes.
The central database is obviously a SPOF (single point of failure). Special care must be taken to garantee that the database is always up and running (cluster, high availability solutions…).
May the front-end not be able to connect to the database, it enters “Fallback Mode”. The front-end tries to response to clients the best way it can. It reloads the server configuration (network topology) cached from the database. This cache is a simple serialization of java objects locally stored on each front-end.
In fallback mode, front-ends are only able to renew existing leases. It is obviously not capable of distributing new addresses to new clients, as this would probably create IP conflicts.
Hot data is modified through stored procedure only. This allows a clear isolation from the different front-ends. Communication between front-end and back-end is done via JDBC. Stored procedures can be considered as “SQL Service” without polluting front-end code with tons of SQL.
There are two ways to launch the server: through CLI, or programmatically in your own application.
The CLI interface is managed through the Service Wrapper module which provides UNIX/Windows launch scripts, and a watch-dog features automatically relaunching the server after an unexpected shutdown.
The main() function is in org.dhcpdj.Server Class.
CLI options are parsed by the arg4j library, looking for -c parameter to specify the bootstrap configuration file. The default location is './conf/dhcpd-j.properties'.
The Server object is instanciated and the content of the properties file passed as intial parameters (see below).
The DHCP Server can be launched programatically in any existing application. You should create a new org.dhcpd-j.Server object with a Properties map.
Valid parameters are:
| config.mode | Server configuration mode (xml, oracle… |
|---|---|
| config.xml.file | Location of the xml file containing the server 'cold' configuration |
| to be completed | TODO: add jdbc connection parameters |
You then call the run() method.
Properties props = new Properties(); props.load("[bootstrap file]"); Server server = new Server(props); server.run();
Note: the method run() returns only at server shutdown.
You may want to run the server in a dedicated thread. To do so, the Server class implements the Runnable class and can be easily launched in a separate thread.
Properties props = new Properties(); props.load("[bootstrap file]"); Server server = new Server(props); Thread dispatchThread = new Thread(server); dispatchThread.start();
As seen in the previous section, the Server is launched with a Properties map passed either through CLI or through programmatic launch.
The first parameter checked is config.mode.
| config.mode | Server configuration mode (xml, oracle…) |
|---|
The /org/dhcpdj/config/ConfigReader.properties contains the mapping between the selected mode and the concrete onfigReader factories to be used.
Currently:
| config.mode | Class |
|---|---|
xml | org.dhcpdj.config.xml.XmlConfigReader |
oracle | To be completed |
The ConfigReader factory is then responsible to instanciate all specific config readers and concrete handling classes.
GlobalConfig, FrontendConfig, TopologyConfig (including dynamic reloading)MainServlet: concrete DHCP Servlet class handling all requestsBackendIntf: generic requests to the back-end
public interface ConfigReader {
public void init(Server dhcpCoreServer, Properties configProperties) throws ConfigException;
public GlobalConfig getGlobalConfig();
public FrontendConfig getFrontEndConfig();
public TopologyConfig getTopologyConfig();
public TopologyConfig reloadTopologyConfig();
public MainServlet makeMainServlet(Server mainServer);
public BackendIntf makeBackEnd();
}
The default mappings are included by default, and should be changed only when introducing new major features:
config.mode | xml | oracle |
|---|---|---|
ConfigReader | org.dhcpdj.config.xml.XmlConfigReader | |
GlobalConfig | org.dhcpdj.config.xml.XmlGlobalConfigReader | |
FrontendConfig | org.dhcpdj.config.xml.XmlFrontEndConfigReader | |
TopologyConfig | org.dhcpdj.config.xml.XmlTopologyConfigReader | |
MainServlet | org.dhcpdj.config.xml.XmlMainServlet | |
BackendIntf | org.dhcpdj.backend.hsql.HsqlBackendServer | |
To be completed
There is a generic object framework for the server front-end. 'Cold' data is loaded either from XML files or from JDBC database, depending on 'config.mode' bootstrap parameter.
There are 4 partitions in the configuration (see Server configuration page):
The configuration is loaded from an xml file, whose location is set in the onfig.xml.file properties parameter.
The corresponding configuration objects are created through the XmlConfigReader factory.
| Configuration base object | xml section in config file |
|---|---|
| org.dhcpdj.config.FrontendConfig | <front-end>…</front-end> |
| org.dhcpdj.config.GlobalConfig | <global>…</global> |
| org.dhcpdj.config.TopologyConfig | <topology>…</topology> |
| TODO | <back-end>…</back-end> |
Schema needed here
When all configuration objects are loaded, the DHCP Servlet is created and launched, see dhcp4java api documentation.
The following parameter are taken from the front-end section of the XML file:
| section in XML file | property equivalent for DHCP Servlet |
|---|---|
| <listen port=[port] inet=[ip] /> | serverAddress “ip:port” |
| <threads core=[core] /> | serverThreads |
| <threads max=[max] /> | serverThreadsMax |
| <threads keepalive=[keepalive] /> | serverThreadsKeepalive |
The DHCP Servlet is running in the same thread as the org.dhcpdj.Server.run() method.
The Server is designed to be able to reload most configuration elements dynamically, without any server restart. This is true for topology section.
The ConfigReader can be asked to reload/reparse a TopologyConfiguration after the server has been started. You may add features to avoid too frequent reloading (1 per minute may be an acceptable limit).
TODO
The Server.run() method calls the DHCPServlet.run() method, thus delegating request handling. The real work is done in the org.dhcpdj.MainServlet class.