From 878bed3207150a3a006eecba1c30292fbf22cda6 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 16 Feb 2012 10:39:01 -0600 Subject: [PATCH 001/148] [trac1687] remove generated guide and message documentation files Later steps will make sure these are generated for "make dist" to be included in tarball. --- doc/guide/bind10-guide.html | 1631 --------- doc/guide/bind10-guide.txt | 1726 ---------- doc/guide/bind10-messages.html | 2628 -------------- doc/guide/bind10-messages.xml | 5896 -------------------------------- 4 files changed, 11881 deletions(-) delete mode 100644 doc/guide/bind10-guide.html delete mode 100644 doc/guide/bind10-guide.txt delete mode 100644 doc/guide/bind10-messages.html delete mode 100644 doc/guide/bind10-messages.xml diff --git a/doc/guide/bind10-guide.html b/doc/guide/bind10-guide.html deleted file mode 100644 index 4ae31f57cc..0000000000 --- a/doc/guide/bind10-guide.html +++ /dev/null @@ -1,1631 +0,0 @@ -BIND 10 Guide

BIND 10 Guide

Administrator Reference for BIND 10

This is the reference guide for BIND 10 version - 20120127.

Abstract

BIND 10 is a framework that features Domain Name System - (DNS) suite and Dynamic Host Configuration Protocol (DHCP) - servers managed by Internet Systems Consortium (ISC). It - includes DNS libraries, modular components for controlling - authoritative and recursive DNS servers, and experimental DHCPv4 - and DHCPv6 servers. -

- This is the reference guide for BIND 10 version 20120127. - The most up-to-date version of this document (in PDF, HTML, - and plain text formats), along with other documents for - BIND 10, can be found at http://bind10.isc.org/docs. -


List of Tables

3.1.

Preface

Table of Contents

1. Acknowledgements

1. Acknowledgements

ISC would like to acknowledge generous support for - BIND 10 development of DHCPv4 and DHCPv6 components provided - by Comcast.

Chapter 1. Introduction

- BIND is the popular implementation of a DNS server, developer - interfaces, and DNS tools. - BIND 10 is a rewrite of BIND 9. BIND 10 is written in C++ and Python - and provides a modular environment for serving and maintaining DNS. - BIND 10 provides a EDNS0- and DNSSEC-capable authoritative - DNS server and a caching recursive name server which also - provides forwarding. -

- This guide covers the experimental prototype of - BIND 10 version 20120127. -

1.1. Supported Platforms

- BIND 10 builds have been tested on Debian GNU/Linux 5 and unstable, - Ubuntu 9.10, NetBSD 5, Solaris 10, FreeBSD 7 and 8, CentOS - Linux 5.3, and MacOS 10.6. - - It has been tested on Sparc, i386, and amd64 hardware - platforms. - - It is planned for BIND 10 to build, install and run on - Windows and standard Unix-type platforms. -

1.2. Required Software

- BIND 10 requires at least Python 3.1 - (http://www.python.org/). - It has also been tested with Python 3.2. -

- BIND 10 uses the Botan crypto library for C++ - (http://botan.randombit.net/). - It requires at least Botan version 1.8. -

- BIND 10 uses the log4cplus C++ logging library - (http://log4cplus.sourceforge.net/). - It requires at least log4cplus version 1.0.3. -

- The authoritative DNS server uses SQLite3 - (http://www.sqlite.org/). - - It needs at least SQLite version 3.3.9. -

- The b10-xfrin, b10-xfrout, - and b10-zonemgr components require the - libpython3 library and the Python _sqlite3.so module - (which is included with Python). - The Python module needs to be built for the corresponding Python 3. -

Note

- Some operating systems do not provide these dependencies - in their default installation nor standard packages - collections. - You may need to install them separately. -

1.3. Starting and Stopping the Server

- BIND 10 is modular. Part of this modularity is - accomplished using multiple cooperating processes which, together, - provide the server functionality. This is a change from - the previous generation of BIND software, which used a - single process. -

- At first, running many different processes may seem confusing. - However, these processes are started, stopped, and maintained - by a single command, bind10. - This command starts a master process which will start other - processes as needed. - The processes started by the bind10 - command have names starting with "b10-", including: -

- -

  • - b10-msgq — - Message bus daemon. - This process coordinates communication between all of the other - BIND 10 processes. -
  • - b10-auth — - Authoritative DNS server. - This process serves DNS requests. -
  • - b10-cfgmgr — - Configuration manager. - This process maintains all of the configuration for BIND 10. -
  • - b10-cmdctl — - Command and control service. - This process allows external control of the BIND 10 system. -
  • - b10-resolver — - Recursive name server. - This process handles incoming queries. - -
  • - b10-stats — - Statistics collection daemon. - This process collects and reports statistics data. -
  • - b10-xfrin — - Incoming zone transfer service. - This process is used to transfer a new copy - of a zone into BIND 10, when acting as a secondary server. -
  • - b10-xfrout — - Outgoing zone transfer service. - This process is used to handle transfer requests to - send a local zone to a remote secondary server, - when acting as a master server. -
  • - b10-zonemgr — - Secondary manager. - This process keeps track of timers and other - necessary information for BIND 10 to act as a slave server. -

-

- These are ran automatically by bind10 - and do not need to be run manually. -

1.4. Managing BIND 10

- Once BIND 10 is running, a few commands are used to interact - directly with the system: -

  • - bindctl — - interactive administration interface. - This is a command-line tool which allows an administrator - to control BIND 10. -
  • - b10-loadzone — - zone file loader. - This tool will load standard masterfile-format zone files into - BIND 10. -
  • - b10-cmdctl-usermgr — - user access control. - This tool allows an administrator to authorize additional users - to manage BIND 10. -

-

- The tools and modules are covered in full detail in this guide. - - In addition, manual pages are also provided in the default installation. -

- BIND 10 also provides libraries and programmer interfaces - for C++ and Python for the message bus, configuration backend, - and, of course, DNS. These include detailed developer - documentation and code examples. - -

Chapter 2. Installation

2.1. Building Requirements

- In addition to the run-time requirements, building BIND 10 - from source code requires various development include headers. -

Note

- Some operating systems have split their distribution packages into - a run-time and a development package. You will need to install - the development package versions, which include header files and - libraries, to build BIND 10 from source code. -

- Building from source code requires the Boost - build-time headers - (http://www.boost.org/). - At least Boost version 1.35 is required. - - -

- To build BIND 10, also install the Botan (at least version - 1.8) and the log4cplus (at least version 1.0.3) - development include headers. -

- Building BIND 10 also requires a C++ compiler and - standard development headers, make, and pkg-config. - BIND 10 builds have been tested with GCC g++ 3.4.3, 4.1.2, - 4.1.3, 4.2.1, 4.3.2, and 4.4.1; Clang++ 2.8; and Sun C++ 5.10. -

- Visit the wiki at http://bind10.isc.org/wiki/SystemSpecificNotes - for system-specific installation tips. -

2.2. Quick start

Note

- This quickly covers the standard steps for installing - and deploying BIND 10 as an authoritative name server using - its defaults. For troubleshooting, full customizations and further - details, see the respective chapters in the BIND 10 guide. -

- To quickly get started with BIND 10, follow these steps. -

  1. - Install required run-time and build dependencies. -
  2. - Download the BIND 10 source tar file from - ftp://ftp.isc.org/isc/bind10/. -
  3. Extract the tar file: -

    $ gzcat bind10-VERSION.tar.gz | tar -xvf -

    -

  4. Go into the source and run configure: -

    $ cd bind10-VERSION
    -  $ ./configure

    -

  5. Build it: -

    $ make

    -

  6. Install it (to default /usr/local): -

    $ make install

    -

  7. Start the server: -

    $ /usr/local/sbin/bind10

    -

  8. Test it; for example: -

    $ dig @127.0.0.1 -c CH -t TXT authors.bind

    -

  9. Load desired zone file(s), for example: -

    $ b10-loadzone your.zone.example.org

    -

  10. - Test the new zone. -

2.3. Installation from source

- BIND 10 is open source software written in C++ and Python. - It is freely available in source code form from ISC via - the Git code revision control system or as a downloadable - tar file. It may also be available in pre-compiled ready-to-use - packages from operating system vendors. -

2.3.1. Download Tar File

- Downloading a release tar file is the recommended method to - obtain the source code. -

- The BIND 10 releases are available as tar file downloads from - ftp://ftp.isc.org/isc/bind10/. - Periodic development snapshots may also be available. -

2.3.2. Retrieve from Git

- Downloading this "bleeding edge" code is recommended only for - developers or advanced users. Using development code in a production - environment is not recommended. -

Note

- When using source code retrieved via Git additional - software will be required: automake (v1.11 or newer), - libtoolize, and autoconf (2.59 or newer). - These may need to be installed. -

- The latest development code, including temporary experiments - and un-reviewed code, is available via the BIND 10 code revision - control system. This is powered by Git and all the BIND 10 - development is public. - The leading development is done in the master. -

- The code can be checked out from - git://git.bind10.isc.org/bind10; - for example: - -

$ git clone git://git.bind10.isc.org/bind10

-

- When checking out the code from - the code version control system, it doesn't include the - generated configure script, Makefile.in files, nor the - related configure files. - They can be created by running autoreconf - with the --install switch. - This will run autoconf, - aclocal, - libtoolize, - autoheader, - automake, - and related commands. -

2.3.3. Configure before the build

- BIND 10 uses the GNU Build System to discover build environment - details. - To generate the makefiles using the defaults, simply run: -

$ ./configure

-

- Run ./configure with the --help - switch to view the different options. The commonly-used options are: - -

--prefix
Define the installation location (the - default is /usr/local/). -
--with-boost-include
Define the path to find the Boost headers. -
--with-pythonpath
Define the path to Python 3.1 if it is not in the - standard execution path. -
--with-gtest
Enable building the C++ Unit Tests using the - Google Tests framework. Optionally this can define the - path to the gtest header files and library. -

- -

- For example, the following configures it to - find the Boost headers, find the - Python interpreter, and sets the installation location: - -

$ ./configure \
-      --with-boost-include=/usr/pkg/include \
-      --with-pythonpath=/usr/pkg/bin/python3.1 \
-      --prefix=/opt/bind10

-

- If the configure fails, it may be due to missing or old - dependencies. -

2.3.4. Build

- After the configure step is complete, to build the executables - from the C++ code and prepare the Python scripts, run: - -

$ make

-

2.3.5. Install

- To install the BIND 10 executables, support files, - and documentation, run: -

$ make install

-

Note

The install step may require superuser privileges.

2.3.6. Install Hierarchy

- The following is the layout of the complete BIND 10 installation: -

  • - bin/ — - general tools and diagnostic clients. -
  • - etc/bind10-devel/ — - configuration files. -
  • - lib/ — - libraries and python modules. -
  • - libexec/bind10-devel/ — - executables that a user wouldn't normally run directly and - are not run independently. - These are the BIND 10 modules which are daemons started by - the bind10 tool. -
  • - sbin/ — - commands used by the system administrator. -
  • - share/bind10-devel/ — - configuration specifications. -
  • - share/man/ — - manual pages (online documentation). -
  • - var/bind10-devel/ — - data source and configuration databases. -

-

Chapter 3. Starting BIND10 with bind10

- BIND 10 provides the bind10 command which - starts up the required processes. - bind10 - will also restart some processes that exit unexpectedly. - This is the only command needed to start the BIND 10 system. -

- After starting the b10-msgq communications channel, - bind10 connects to it, - runs the configuration manager, and reads its own configuration. - Then it starts the other modules. -

- The b10-sockcreator, b10-msgq and - b10-cfgmgr - services make up the core. The b10-msgq daemon - provides the communication channel between every part of the system. - The b10-cfgmgr daemon is always needed by every - module, if only to send information about themselves somewhere, - but more importantly to ask about their own settings, and - about other modules. The b10-sockcreator will - allocate sockets for the rest of the system. -

- In its default configuration, the bind10 - master process will also start up - b10-cmdctl for admins to communicate with the - system, b10-auth for authoritative DNS service, - b10-stats for statistics collection, - b10-xfrin for inbound DNS zone transfers, - b10-xfrout for outbound DNS zone transfers, - and b10-zonemgr for secondary service. -

3.1. Starting BIND 10

- To start the BIND 10 service, simply run bind10. - Run it with the --verbose switch to - get additional debugging or diagnostic output. -

Note

- If the setproctitle Python module is detected at start up, - the process names for the Python-based daemons will be renamed - to better identify them instead of just python. - This is not needed on some operating systems. -

3.2. Configuration of started processes

- The processes to be started can be configured, with the exception - of the b10-sockcreator, b10-msgq - and b10-cfgmgr. -

- The configuration is in the Boss/components section. Each element - represents one component, which is an abstraction of a process - (currently there's also one component which doesn't represent - a process). If you didn't want to transfer out at all (your server - is a slave only), you would just remove the corresponding component - from the set, like this and the process would be stopped immediately - (and not started on the next startup): -

> config remove Boss/components b10-xfrout
-> config commit

-

- To add a process to the set, let's say the resolver (which not started - by default), you would do this: -

> config add Boss/components b10-resolver
-> config set Boss/components/b10-resolver/special resolver
-> config set Boss/components/b10-resolver/kind needed
-> config set Boss/components/b10-resolver/priority 10
-> config commit

- Now, what it means. We add an entry called b10-resolver. It is both a - name used to reference this component in the configuration and the - name of the process to start. Then we set some parameters on how to - start it. -

- The special one is for components that need some kind of special care - during startup or shutdown. Unless specified, the component is started - in usual way. This is the list of components that need to be started - in a special way, with the value of special used for them: -

Table 3.1. 

ComponentSpecialDescription
b10-authauthAuthoritative server
b10-resolverresolverThe resolver
b10-cmdctlcmdctlThe command control (remote control interface)


-

- The kind specifies how a failure of the component should - be handled. If it is set to dispensable - (the default unless you set something else), it will get - started again if it fails. If it is set to needed - and it fails at startup, the whole bind10 - shuts down and exits with error exit code. But if it fails - some time later, it is just started again. If you set it - to core, you indicate that the system is - not usable without the component and if such component - fails, the system shuts down no matter when the failure - happened. This is the behaviour of the core components - (the ones you can't turn off), but you can declare any - other components as core as well if you wish (but you can - turn these off, they just can't fail). -

- The priority defines order in which the components should start. - The ones with higher number are started sooner than the ones with - lower ones. If you don't set it, 0 (zero) is used as the priority. - Usually, leaving it at the default is enough. -

- There are other parameters we didn't use in our example. - One of them is address. It is the address - used by the component on the b10-msgq - message bus. The special components already know their - address, but the usual ones don't. The address is by - convention the thing after b10-, with - the first letter capital (eg. b10-stats - would have Stats as its address). - -

- The last one is process. It is the name of the process to be started. - It defaults to the name of the component if not set, but you can use - this to override it. -

Note

- This system allows you to start the same component multiple times - (by including it in the configuration with different names, but the - same process setting). However, the rest of the system doesn't expect - such situation, so it would probably not do what you want. Such - support is yet to be implemented. -

Note

- The configuration is quite powerful, but that includes - a lot of space for mistakes. You could turn off the - b10-cmdctl, but then you couldn't - change it back the usual way, as it would require it to - be running (you would have to find and edit the configuration - directly). Also, some modules might have dependencies - -- b10-stats-httpd need - b10-stats, b10-xfrout - needs the b10-auth to be running, etc. - - - -

- In short, you should think twice before disabling something here. -

- It is possible to start some components multiple times (currently - b10-auth and b10-resolzer). - You might want to do that to gain more performance (each one uses only - single core). Just put multiple entries under different names, like - this, with the same config: -

> config add Boss/components b10-resolver-2
-> config set Boss/components/b10-resolver-2/special resolver
-> config set Boss/components/b10-resolver-2/kind needed
-> config commit

-

- However, this is work in progress and the support is not yet complete. - For example, each resolver will have its own cache, each authoritative - server will keep its own copy of in-memory data and there could be - problems with locking the sqlite database, if used. The configuration - might be changed to something more convenient in future. -

Chapter 4. Command channel

- The BIND 10 components use the b10-msgq - message routing daemon to communicate with other BIND 10 components. - The b10-msgq implements what is called the - Command Channel. - Processes intercommunicate by sending messages on the command - channel. - Example messages include shutdown, get configurations, and set - configurations. - This Command Channel is not used for DNS message passing. - It is used only to control and monitor the BIND 10 system. -

- Administrators do not communicate directly with the - b10-msgq daemon. - By default, BIND 10 uses port 9912 for the - b10-msgq service. - It listens on 127.0.0.1. -

Chapter 5. Configuration manager

- The configuration manager, b10-cfgmgr, - handles all BIND 10 system configuration. It provides - persistent storage for configuration, and notifies running - modules of configuration changes. -

- The b10-auth and b10-xfrin - daemons and other components receive their configurations - from the configuration manager over the b10-msgq - command channel. -

The administrator doesn't connect to it directly, but - uses a user interface to communicate with the configuration - manager via b10-cmdctl's REST-ful interface. - b10-cmdctl is covered in Chapter 6, Remote control daemon. -

Note

- The development prototype release only provides the - bindctl as a user interface to - b10-cmdctl. - Upcoming releases will provide another interactive command-line - interface and a web-based interface. -

- The b10-cfgmgr daemon can send all - specifications and all current settings to the - bindctl client (via - b10-cmdctl). -

- b10-cfgmgr relays configurations received - from b10-cmdctl to the appropriate modules. -

- The stored configuration file is at - /usr/local/var/bind10-devel/b10-config.db. - (The full path is what was defined at build configure time for - --localstatedir. - The default is /usr/local/var/.) - The format is loosely based on JSON and is directly parseable - python, but this may change in a future version. - This configuration data file is not manually edited by the - administrator. -

- The configuration manager does not have any command line arguments. - Normally it is not started manually, but is automatically - started using the bind10 master process - (as covered in Chapter 3, Starting BIND10 with bind10). -

Chapter 6. Remote control daemon

- b10-cmdctl is the gateway between - administrators and the BIND 10 system. - It is a HTTPS server that uses standard HTTP Digest - Authentication for username and password validation. - It provides a REST-ful interface for accessing and controlling - BIND 10. -

- When b10-cmdctl starts, it firsts - asks b10-cfgmgr about what modules are - running and what their configuration is (over the - b10-msgq channel). Then it will start listening - on HTTPS for clients — the user interface — such - as bindctl. -

- b10-cmdctl directly sends commands - (received from the user interface) to the specified component. - Configuration changes are actually commands to - b10-cfgmgr so are sent there. -

The HTTPS server requires a private key, - such as a RSA PRIVATE KEY. - The default location is at - /usr/local/etc/bind10-devel/cmdctl-keyfile.pem. - (A sample key is at - /usr/local/share/bind10-devel/cmdctl-keyfile.pem.) - It also uses a certificate located at - /usr/local/etc/bind10-devel/cmdctl-certfile.pem. - (A sample certificate is at - /usr/local/share/bind10-devel/cmdctl-certfile.pem.) - This may be a self-signed certificate or purchased from a - certification authority. -

Note

- The HTTPS server doesn't support a certificate request from a - client (at this time). - - The b10-cmdctl daemon does not provide a - public service. If any client wants to control BIND 10, then - a certificate needs to be first received from the BIND 10 - administrator. - The BIND 10 installation provides a sample PEM bundle that matches - the sample key and certificate. -

- The b10-cmdctl daemon also requires - the user account file located at - /usr/local/etc/bind10-devel/cmdctl-accounts.csv. - This comma-delimited file lists the accounts with a user name, - hashed password, and salt. - (A sample file is at - /usr/local/share/bind10-devel/cmdctl-accounts.csv. - It contains the user named root with the password - bind10.) -

- The administrator may create a user account with the - b10-cmdctl-usermgr tool. -

- By default the HTTPS server listens on the localhost port 8080. - The port can be set by using the --port command line option. - The address to listen on can be set using the --address command - line argument. - Each HTTPS connection is stateless and timesout in 1200 seconds - by default. This can be - redefined by using the --idle-timeout command line argument. -

6.1. Configuration specification for b10-cmdctl

- The configuration items for b10-cmdctl are: -key_file -cert_file -accounts_file -

- The control commands are: -print_settings - - -shutdown -

Chapter 7. Control and configure user interface

Note

- For this development prototype release, bindctl - is the only user interface. It is expected that upcoming - releases will provide another interactive command-line - interface and a web-based interface for controlling and - configuring BIND 10. -

- The bindctl tool provides an interactive - prompt for configuring, controlling, and querying the BIND 10 - components. - It communicates directly with a REST-ful interface over HTTPS - provided by b10-cmdctl. It doesn't - communicate to any other components directly. -

- Configuration changes are actually commands to - b10-cfgmgr. So when bindctl - sends a configuration, it is sent to b10-cmdctl - (over a HTTPS connection); then b10-cmdctl - sends the command (over a b10-msgq command - channel) to b10-cfgmgr which then stores - the details and relays (over a b10-msgq command - channel) the configuration on to the specified module. -

-

Chapter 8. Authoritative Server

- The b10-auth is the authoritative DNS server. - It supports EDNS0 and DNSSEC. It supports IPv6. - Normally it is started by the bind10 master - process. -

8.1. Server Configurations

- b10-auth is configured via the - b10-cfgmgr configuration manager. - The module name is Auth. - The configuration data item is: - -

database_file
This is an optional string to define the path to find - the SQLite3 database file. - -Note: Later the DNS server will use various data source backends. -This may be a temporary setting until then. -

- -

- - The configuration command is: - -

shutdown
Stop the authoritative DNS server. -

- -

8.2. Data Source Backends

Note

- For the development prototype release, b10-auth - supports a SQLite3 data source backend and in-memory data source - backend. - Upcoming versions will be able to use multiple different - data sources, such as MySQL and Berkeley DB. -

- By default, the SQLite3 backend uses the data file located at - /usr/local/var/bind10-devel/zone.sqlite3. - (The full path is what was defined at build configure time for - --localstatedir. - The default is /usr/local/var/.) - This data file location may be changed by defining the - database_file configuration. -

8.3. Loading Master Zones Files

- RFC 1035 style DNS master zone files may imported - into a BIND 10 data source by using the - b10-loadzone utility. -

- b10-loadzone supports the following - special directives (control entries): - -

$INCLUDE
Loads an additional zone file. This may be recursive. -
$ORIGIN
Defines the relative domain name. -
$TTL
Defines the time-to-live value used for following - records that don't include a TTL. -

- -

- The -o argument may be used to define the - default origin for loaded zone file records. -

Note

- In the development prototype release, only the SQLite3 back - end is used. - By default, it stores the zone data in - /usr/local/var/bind10-devel/zone.sqlite3 - unless the -d switch is used to set the - database filename. - Multiple zones are stored in a single SQLite3 zone database. -

- If you reload a zone already existing in the database, - all records from that prior zone disappear and a whole new set - appears. -

Chapter 9. Incoming Zone Transfers

- Incoming zones are transferred using the b10-xfrin - process which is started by bind10. - When received, the zone is stored in the corresponding BIND 10 - data source, and its records can be served by - b10-auth. - In combination with b10-zonemgr (for - automated SOA checks), this allows the BIND 10 server to - provide secondary service. -

- The b10-xfrin process supports both AXFR and - IXFR. Due to some implementation limitations of the current - development release, however, it only tries AXFR by default, - and care should be taken to enable IXFR. -

Note

- In the current development release of BIND 10, incoming zone - transfers are only available for SQLite3-based data sources, - that is, they don't work for an in-memory data source. -

9.1. Configuration for Incoming Zone Transfers

- In practice, you need to specify a list of secondary zones to - enable incoming zone transfers for these zones (you can still - trigger a zone transfer manually, without a prior configuration - (see below)). -

- For example, to enable zone transfers for a zone named "example.com" - (whose master address is assumed to be 2001:db8::53 here), - run the following at the bindctl prompt: - -

> config add Xfrin/zones
-> config set Xfrin/zones[0]/name "example.com"
-> config set Xfrin/zones[0]/master_addr "2001:db8::53"
-> config commit

- - (We assume there has been no zone configuration before). -

9.2. Enabling IXFR

- As noted above, b10-xfrin uses AXFR for - zone transfers by default. To enable IXFR for zone transfers - for a particular zone, set the use_ixfr - configuration parameter to true. - In the above example of configuration sequence, you'll need - to add the following before performing commit: -

> config set Xfrin/zones[0]/use_ixfr true

-

Note

- One reason why IXFR is disabled by default in the current - release is because it does not support automatic fallback from IXFR to - AXFR when it encounters a primary server that doesn't support - outbound IXFR (and, not many existing implementations support - it). Another, related reason is that it does not use AXFR even - if it has no knowledge about the zone (like at the very first - time the secondary server is set up). IXFR requires the - "current version" of the zone, so obviously it doesn't work - in this situation and AXFR is the only workable choice. - The current release of b10-xfrin does not - make this selection automatically. - These features will be implemented in a near future - version, at which point we will enable IXFR by default. -

9.3. Secondary Manager

- The b10-zonemgr process is started by - bind10. - It keeps track of SOA refresh, retry, and expire timers - and other details for BIND 10 to perform as a slave. - When the b10-auth authoritative DNS server - receives a NOTIFY message, b10-zonemgr - may tell b10-xfrin to do a refresh - to start an inbound zone transfer. - The secondary manager resets its counters when a new zone is - transferred in. -

Note

- Access control (such as allowing notifies) is not yet provided. - The primary/secondary service is not yet complete. -

- The following example shows using bindctl - to configure the server to be a secondary for the example zone: - -

> config add Zonemgr/secondary_zones
-> config set Zonemgr/secondary_zones[0]/name "example.com"
-> config set Zonemgr/secondary_zones[0]/class "IN"
-> config commit

- - - -

- If the zone does not exist in the data source already - (i.e. no SOA record for it), b10-zonemgr - will automatically tell b10-xfrin - to transfer the zone in. -

9.4. Trigger an Incoming Zone Transfer Manually

- To manually trigger a zone transfer to retrieve a remote zone, - you may use the bindctl utility. - For example, at the bindctl prompt run: - -

> Xfrin retransfer zone_name="foo.example.org" master=192.0.2.99

-

Chapter 10. Outbound Zone Transfers

- The b10-xfrout process is started by - bind10. - When the b10-auth authoritative DNS server - receives an AXFR or IXFR request, b10-auth - internally forwards the request to b10-xfrout, - which handles the rest of request processing. - This is used to provide primary DNS service to share zones - to secondary name servers. - The b10-xfrout is also used to send - NOTIFY messages to secondary servers. -

- A global or per zone transfer_acl configuration - can be used to control accessibility of the outbound zone - transfer service. - By default, b10-xfrout allows any clients to - perform zone transfers for any zones: -

> config show Xfrout/transfer_acl
-Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)

- You can change this to, for example, rejecting all transfer - requests by default while allowing requests for the transfer - of zone "example.com" from 192.0.2.1 and 2001:db8::1 as follows: -

> config set Xfrout/transfer_acl[0] {"action": "REJECT"}
-> config add Xfrout/zone_config
-> config set Xfrout/zone_config[0]/origin "example.com"
-> config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1"},
-                                                 {"action": "ACCEPT", "from": "2001:db8::1"}]
-> config commit

Note

- In the above example the lines - for transfer_acl were divided for - readability. In the actual input it must be in a single line. -

- If you want to require TSIG in access control, a separate TSIG - "key ring" must be configured specifically - for b10-xfrout as well as a system wide - key ring, both containing a consistent set of keys. - For example, to change the previous example to allowing requests - from 192.0.2.1 signed by a TSIG with a key name of - "key.example", you'll need to do this: -

> config set tsig_keys/keys ["key.example:<base64-key>"]
-> config set Xfrout/tsig_keys/keys ["key.example:<base64-key>"]
-> config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1", "key": "key.example"}]
-> config commit

- The first line of configuration defines a system wide key ring. - This is necessary because the b10-auth server - also checks TSIGs and it uses the system wide configuration. -

Note

- In a future version, b10-xfrout will also - use the system wide TSIG configuration. - The way to specify zone specific configuration (ACLs, etc) is - likely to be changed, too. -

Chapter 11. Recursive Name Server

- The b10-resolver process is started by - bind10. - -

- The main bind10 process can be configured - to select to run either the authoritative or resolver or both. - By default, it starts the authoritative service. - - - You may change this using bindctl, for example: - -

-> config remove Boss/components b10-xfrout
-> config remove Boss/components b10-xfrin
-> config remove Boss/components b10-auth
-> config add Boss/components b10-resolver
-> config set Boss/components/b10-resolver/special resolver
-> config set Boss/components/b10-resolver/kind needed
-> config set Boss/components/b10-resolver/priority 10
-> config commit
-

- -

- The master bind10 will stop and start - the desired services. -

- By default, the resolver listens on port 53 for 127.0.0.1 and ::1. - The following example shows how it can be configured to - listen on an additional address (and port): - -

-> config add Resolver/listen_on
-> config set Resolver/listen_on[2]/address "192.168.1.1"
-> config set Resolver/listen_on[2]/port 53
-> config commit
-

-

(Replace the 2 - as needed; run config show - Resolver/listen_on if needed.)

11.1. Access Control

- By default, the b10-resolver daemon only accepts - DNS queries from the localhost (127.0.0.1 and ::1). - The Resolver/query_acl configuration may - be used to reject, drop, or allow specific IPs or networks. - This configuration list is first match. -

- The configuration's action item may be - set to ACCEPT to allow the incoming query, - REJECT to respond with a DNS REFUSED return - code, or DROP to ignore the query without - any response (such as a blackhole). For more information, - see the respective debugging messages: RESOLVER_QUERY_ACCEPTED, - RESOLVER_QUERY_REJECTED, - and RESOLVER_QUERY_DROPPED. -

- The required configuration's from item is set - to an IPv4 or IPv6 address, addresses with an network mask, or to - the special lowercase keywords any6 (for - any IPv6 address) or any4 (for any IPv4 - address). -

- For example to allow the 192.168.1.0/24 - network to use your recursive name server, at the - bindctl prompt run: -

-> config add Resolver/query_acl
-> config set Resolver/query_acl[2]/action "ACCEPT"
-> config set Resolver/query_acl[2]/from "192.168.1.0/24"
-> config commit
-

(Replace the 2 - as needed; run config show - Resolver/query_acl if needed.)

Note

This prototype access control configuration - syntax may be changed.

11.2. Forwarding

- - To enable forwarding, the upstream address and port must be - configured to forward queries to, such as: - -

-> config set Resolver/forward_addresses [{ "address": "192.168.1.1", "port": 53 }]
-> config commit
-

- - (Replace 192.168.1.1 to point to your - full resolver.) -

- Normal iterative name service can be re-enabled by clearing the - forwarding address(es); for example: - -

-> config set Resolver/forward_addresses []
-> config commit
-

-

Chapter 12. DHCPv4 Server

Dynamic Host Configuration Protocol for IPv4 (DHCP or - DHCPv4) and Dynamic Host Configuration Protocol for IPv6 (DHCPv6) - are protocols that allow one node (server) to provision - configuration parameters to many hosts and devices (clients). To - ease deployment in larger networks, additional nodes (relays) may - be deployed that facilitate communication between servers and - clients. Even though principles of both DHCPv4 and DHCPv6 are - somewhat similar, these are two radically different - protocols. BIND10 offers server implementations for both DHCPv4 - and DHCPv6. This chapter is about DHCP for IPv4. For a description - of the DHCPv6 server, see Chapter 13, DHCPv6 Server.

The DHCPv4 server component is currently under intense - development. You may want to check out BIND10 DHCP (Kea) wiki - and recent posts on BIND10 - developers mailing list.

The DHCPv4 and DHCPv6 components in BIND10 architecture are - internally code named Kea.

Note

- As of December 2011, both DHCPv4 and DHCPv6 components are - skeleton servers. That means that while they are capable of - performing DHCP configuration, they are not fully functional - yet. In particular, neither has functional lease - databases. This means that they will assign the same, fixed, - hardcoded addresses to any client that will ask. See Section 12.4, “DHCPv4 Server Limitations” and Section 13.4, “DHCPv6 Server Limitations” for - detailed description. -

12.1. DHCPv4 Server Usage

BIND10 provides the DHCPv4 server component since December - 2011. It is a skeleton server and can be described as an early - prototype that is not fully functional yet. It is mature enough - to conduct first tests in lab environment, but it has - significant limitations. See Section 12.4, “DHCPv4 Server Limitations” for - details. -

- The DHCPv4 server is implemented as b10-dhcp4 - daemon. As it is not configurable yet, it is fully autonomous, - that is it does not interact with b10-cfgmgr. - To start DHCPv4 server, simply input: - -

-#cd src/bin/dhcp4
-#./b10-dhcp4
-

- - Depending on your installation, b10-dhcp4 - binary may reside in src/bin/dhcp4 in your source code - directory, in /usr/local/bin/b10-dhcp4 or other directory - you specified during compilation. - - At start, the server will detect available network interfaces - and will attempt to open UDP sockets on all interfaces that - are up, running, are not loopback, and have IPv4 address - assigned. - - The server will then listen to incoming traffic. Currently - supported client messages are DISCOVER and REQUEST. The server - will respond to them with OFFER and ACK, respectively. - - Since the DHCPv4 server opens privileged ports, it requires root - access. Make sure you run this daemon as root.

Note

- Integration with bind10 is - planned. Ultimately, b10-dhcp4 will not - be started directly, but rather via - bind10. Please be aware of this planned - change. -

12.2. DHCPv4 Server Configuration

- The DHCPv4 server does not have a lease database implemented yet - nor any support for configuration, so every time the same set - of configuration options (including the same fixed address) - will be assigned every time. -

- At this stage of development, the only way to alter the server - configuration is to tweak its source code. To do so, please - edit src/bin/dhcp4/dhcp4_srv.cc file and modify following - parameters and recompile: -

-const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease
-const std::string HARDCODED_NETMASK = "255.255.255.0";
-const uint32_t    HARDCODED_LEASE_TIME = 60; // in seconds
-const std::string HARDCODED_GATEWAY = "192.0.2.1";
-const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
-const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
-const std::string HARDCODED_SERVER_ID = "192.0.2.1";

- - Lease database and configuration support is planned for 2012. -

12.3. Supported standards

The following standards and draft standards are currently - supported:

  • RFC2131: Supported messages are DISCOVER, OFFER, - REQUEST, and ACK.
  • RFC2132: Supported options are: PAD (0), - END(255), Message Type(53), DHCP Server Identifier (54), - Domain Name (15), DNS Servers (6), IP Address Lease Time - (51), Subnet mask (1), and Routers (3).

12.4. DHCPv4 Server Limitations

These are the current limitations of the DHCPv4 server - software. Most of them are reflections of the early stage of - development and should be treated as not implemented - yet, rather than actual limitations.

  • During initial IPv4 node configuration, the - server is expected to send packets to a node that does not - have IPv4 address assigned yet. The server requires - certain tricks (or hacks) to transmit such packets. This - is not implemented yet, therefore DHCPv4 server supports - relayed traffic only (that is, normal point to point - communication).
  • b10-dhcp4 provides a single, - fixed, hardcoded lease to any client that asks. There is - no lease manager implemented. If two clients request - addresses, they will both get the same fixed - address.
  • b10-dhcp4 does not support any - configuration mechanisms yet. The whole configuration is - currently hardcoded. The only way to tweak configuration - is to directly modify source code. See see Section 12.2, “DHCPv4 Server Configuration” for details.
  • Upon start, the server will open sockets on all - interfaces that are not loopback, are up and running and - have IPv4 address. Support for multiple interfaces is not - coded in reception routines yet, so if you are running - this code on a machine that has many interfaces and - b10-dhcp4 happens to listen on wrong - interface, the easiest way to work around this problem is - to turn down other interfaces. This limitation will be - fixed shortly.
  • PRL (Parameter Request List, a list of options - requested by a client) is currently ignored and server - assigns DNS SERVER and DOMAIN NAME options.
  • b10-dhcp4 does not support - BOOTP. That is a design choice. This limitation is - permanent. If you have legacy nodes that can't use DHCP and - require BOOTP support, please use latest version of ISC DHCP - http://www.isc.org/software/dhcp.
  • Interface detection is currently working on Linux - only. See Section 14.1, “Interface detection” for details.
  • b10-dhcp4 does not verify that - assigned address is unused. According to RFC2131, the - allocating server should verify that address is no used by - sending ICMP echo request.
  • Address renewal (RENEW), rebinding (REBIND), - confirmation (CONFIRM), duplication report (DECLINE) and - release (RELEASE) are not supported yet.
  • DNS Update is not supported yet.
  • -v (verbose) command line option is currently - the default, and cannot be disabled.

Chapter 13. DHCPv6 Server

Dynamic Host Configuration Protocol for IPv6 (DHCPv6) is - specified in RFC3315. BIND10 provides DHCPv6 server implementation - that is described in this chapter. For a description of the DHCPv4 - server implementation, see Chapter 12, DHCPv4 Server. -

The DHCPv6 server component is currently under intense - development. You may want to check out BIND10 DHCP (Kea) wiki - and recent posts on BIND10 - developers mailing list.

The DHCPv4 and DHCPv6 components in BIND10 architecture are - internally code named Kea.

Note

- As of December 2011, both DHCPv4 and DHCPv6 components are - skeleton servers. That means that while they are capable of - performing DHCP configuration, they are not fully functional - yet. In particular, neither has functional lease - databases. This means that they will assign the same, fixed, - hardcoded addresses to any client that will ask. See Section 12.4, “DHCPv4 Server Limitations” and Section 13.4, “DHCPv6 Server Limitations” for - detailed description. -

13.1. DHCPv6 Server Usage

- BIND10 provides the DHCPv6 server component since September - 2011. It is a skeleton server and can be described as an early - prototype that is not fully functional yet. It is mature - enough to conduct first tests in lab environment, but it has - significant limitations. See Section 13.4, “DHCPv6 Server Limitations” for - details. -

- The DHCPv6 server is implemented as b10-dhcp6 - daemon. As it is not configurable yet, it is fully autonomous, - that is it does not interact with b10-cfgmgr. - To start DHCPv6 server, simply input: - -

-#cd src/bin/dhcp6
-#./b10-dhcp6
-

- - Depending on your installation, b10-dhcp6 - binary may reside in src/bin/dhcp6 in your source code - directory, in /usr/local/bin/b10-dhcp6 or other directory - you specified during compilation. - - At start, server will detect available network interfaces - and will attempt to open UDP sockets on all interfaces that - are up, running, are not loopback, are multicast-capable, and - have IPv6 address assigned. - - The server will then listen to incoming traffic. Currently - supported client messages are SOLICIT and REQUEST. The server - will respond to them with ADVERTISE and REPLY, respectively. - - Since the DHCPv6 server opens privileged ports, it requires root - access. Make sure you run this daemon as root. -

Note

- Integration with bind10 is - planned. Ultimately, b10-dhcp6 will not - be started directly, but rather via - bind10. Please be aware of this planned - change. -

13.2. DHCPv6 Server Configuration

- The DHCPv6 server does not have lease database implemented yet - or any support for configuration, so every time the same set - of configuration options (including the same fixed address) - will be assigned every time. -

- At this stage of development, the only way to alter server - configuration is to tweak its source code. To do so, please - edit src/bin/dhcp6/dhcp6_srv.cc file and modify following - parameters and recompile: -

-const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
-const uint32_t HARDCODED_T1 = 1500; // in seconds
-const uint32_t HARDCODED_T2 = 2600; // in seconds
-const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds
-const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
-const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";

- - Lease database and configuration support is planned for 2012. -

13.3. Supported DHCPv6 Standards

The following standards and draft standards are currently - supported:

  • RFC3315: Supported messages are SOLICIT, - ADVERTISE, REQUEST, and REPLY. Supported options are - SERVER_ID, CLIENT_ID, IA_NA, and IAADDRESS.
  • RFC3646: Supported option is DNS_SERVERS.

13.4. DHCPv6 Server Limitations

These are the current limitations of the DHCPv6 server - software. Most of them are reflections of the early stage of - development and should be treated as not implemented - yet, rather than actual limitations.

-

  • Relayed traffic is not supported.
  • b10-dhcp6 provides a single, - fixed, hardcoded lease to any client that asks. There is no - lease manager implemented. If two clients request addresses, - they will both get the same fixed address.
  • b10-dhcp6 does not support any - configuration mechanisms yet. The whole configuration is - currently hardcoded. The only way to tweak configuration - is to directly modify source code. See see Section 13.2, “DHCPv6 Server Configuration” for details.
  • Upon start, the server will open sockets on all - interfaces that are not loopback, are up, running and are - multicast capable and have IPv6 address. Support for - multiple interfaces is not coded in reception routines yet, - so if you are running this code on a machine that has many - interfaces and b10-dhcp6 happens to - listen on wrong interface, the easiest way to work around - this problem is to turn down other interfaces. This - limitation will be fixed shortly.
  • ORO (Option Request Option, a list of options - requested by a client) is currently ignored and server - assigns DNS SERVER option.
  • Temporary addresses are not supported yet.
  • Prefix delegation is not supported yet.
  • Address renewal (RENEW), rebinding (REBIND), - confirmation (CONFIRM), duplication report (DECLINE) and - release (RELEASE) are not supported yet.
  • DNS Update is not supported yet.
  • Interface detection is currently working on Linux - only. See Section 14.1, “Interface detection” for details.
  • -v (verbose) command line option is currently the - default, and cannot be disabled.

-

Chapter 14. libdhcp++ library

libdhcp++ is a common library written in C++ that handles - many DHCP-related tasks, like DHCPv4 and DHCPv6 packets parsing, - manipulation and assembly, option parsing, manipulation and - assembly, network interface detection and socket operations, like - socket creations, data transmission and reception and socket - closing. -

- While this library is currently used by - b10-dhcp4 and b10-dhcp6 - only, it is designed to be portable, universal library useful for - any kind of DHCP-related software. -

14.1. Interface detection

Both DHCPv4 and DHCPv6 components share network - interface detection routines. Interface detection is - currently only supported on Linux systems.

For non-Linux systems, there is currently stub - implementation provided. As DHCP servers need to know available - addresses, there is a simple mechanism implemented to provide - that information. User is expected to create interfaces.txt - file. Format of this file is simple. It contains list of - interfaces along with available address on each interface. This - mechanism is temporary and is going to be removed as soon as - interface detection becomes available on non-Linux - systems. Here is an example of the interfaces.txt file: -

-# For DHCPv6, please specify link-local address (starts with fe80::)
-# If in doubt, check output of 'ifconfig -a' command.
-eth0 fe80::21e:8cff:fe9b:7349
-
-# For DHCPv4, please use following format:
-#eth0 192.0.2.5

-

14.2. DHCPv4/DHCPv6 packet handling

TODO: Describe packet handling here, with pointers to wiki

Chapter 15. Statistics

- The b10-stats process is started by - bind10. - It periodically collects statistics data from various modules - and aggregates it. - -

- - This stats daemon provides commands to identify if it is - running, show specified or all statistics data, show specified - or all statistics data schema, and set specified statistics - data. - - For example, using bindctl: - -

-> Stats show
-{
-    "Auth": {
-        "opcode.iquery": 0,
-        "opcode.notify": 10,
-        "opcode.query": 869617,
-        ...
-        "queries.tcp": 1749,
-        "queries.udp": 867868
-    },
-    "Boss": {
-        "boot_time": "2011-01-20T16:59:03Z"
-    },
-    "Stats": {
-        "boot_time": "2011-01-20T16:59:05Z",
-        "last_update_time": "2011-01-20T17:04:05Z",
-        "lname": "4d3869d9_a@jreed.example.net",
-        "report_time": "2011-01-20T17:04:06Z",
-        "timestamp": 1295543046.823504
-    }
-}
-       

-

Chapter 16. Logging

16.1. Logging configuration

- - The logging system in BIND 10 is configured through the - Logging module. All BIND 10 modules will look at the - configuration in Logging to see what should be logged and - to where. - - - -

16.1.1. Loggers

- - Within BIND 10, a message is logged through a component - called a "logger". Different parts of BIND 10 log messages - through different loggers, and each logger can be configured - independently of one another. - -

- - In the Logging module, you can specify the configuration - for zero or more loggers; any that are not specified will - take appropriate default values.. - -

- - The three most important elements of a logger configuration - are the name (the component that is - generating the messages), the severity - (what to log), and the output_options - (where to log). - -

16.1.1.1. name (string)

- Each logger in the system has a name, the name being that - of the component using it to log messages. For instance, - if you want to configure logging for the resolver module, - you add an entry for a logger named Resolver. This - configuration will then be used by the loggers in the - Resolver module, and all the libraries used by it. -

- - If you want to specify logging for one specific library - within the module, you set the name to - module.library. For example, the - logger used by the nameserver address store component - has the full name of Resolver.nsas. If - there is no entry in Logging for a particular library, - it will use the configuration given for the module. - - - -

- - - - To illustrate this, suppose you want the cache library - to log messages of severity DEBUG, and the rest of the - resolver code to log messages of severity INFO. To achieve - this you specify two loggers, one with the name - Resolver and severity INFO, and one with - the name Resolver.cache with severity - DEBUG. As there are no entries for other libraries (e.g. - the nsas), they will use the configuration for the module - (Resolver), so giving the desired behavior. - -

- - One special case is that of a module name of * - (asterisks), which is interpreted as any - module. You can set global logging options by using this, - including setting the logging configuration for a library - that is used by multiple modules (e.g. *.config - specifies the configuration library code in whatever - module is using it). - -

- - If there are multiple logger specifications in the - configuration that might match a particular logger, the - specification with the more specific logger name takes - precedence. For example, if there are entries for for - both * and Resolver, the - resolver module — and all libraries it uses — - will log messages according to the configuration in the - second entry (Resolver). All other modules - will use the configuration of the first entry - (*). If there was also a configuration - entry for Resolver.cache, the cache library - within the resolver would use that in preference to the - entry for Resolver. - -

- - One final note about the naming. When specifying the - module name within a logger, use the name of the module - as specified in bindctl, e.g. - Resolver for the resolver module, - Xfrout for the xfrout module, etc. When - the message is logged, the message will include the name - of the logger generating the message, but with the module - name replaced by the name of the process implementing - the module (so for example, a message generated by the - Auth.cache logger will appear in the output - with a logger name of b10-auth.cache). - -

16.1.1.2. severity (string)

- - This specifies the category of messages logged. - Each message is logged with an associated severity which - may be one of the following (in descending order of - severity): -

  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG

- - When the severity of a logger is set to one of these - values, it will only log messages of that severity, and - the severities above it. The severity may also be set to - NONE, in which case all messages from that logger are - inhibited. - - - -

16.1.1.3. output_options (list)

- - Each logger can have zero or more - output_options. These specify where log - messages are sent to. These are explained in detail below. - -

- - The other options for a logger are: - -

16.1.1.4. debuglevel (integer)

- - When a logger's severity is set to DEBUG, this value - specifies what debug messages should be printed. It ranges - from 0 (least verbose) to 99 (most verbose). -

- - If severity for the logger is not DEBUG, this value is ignored. - -

16.1.1.5. additive (true or false)

- - If this is true, the output_options from - the parent will be used. For example, if there are two - loggers configured; Resolver and - Resolver.cache, and additive - is true in the second, it will write the log messages - not only to the destinations specified for - Resolver.cache, but also to the destinations - as specified in the output_options in - the logger named Resolver. - - - -

16.1.2. Output Options

- - The main settings for an output option are the - destination and a value called - output, the meaning of which depends on - the destination that is set. - -

16.1.2.1. destination (string)

- - The destination is the type of output. It can be one of: - -

  • console
  • file
  • syslog

16.1.2.2. output (string)

- - Depending on what is set as the output destination, this - value is interpreted as follows: - -

destination is console
- The value of output must be one of stdout - (messages printed to standard output) or - stderr (messages printed to standard - error). -
destination is file
- The value of output is interpreted as a file name; - log messages will be appended to this file. -
destination is syslog
- The value of output is interpreted as the - syslog facility (e.g. - local0) that should be used - for log messages. -

- - The other options for output_options are: - -

16.1.2.2.1. flush (true of false)

- Flush buffers after each log message. Doing this will - reduce performance but will ensure that if the program - terminates abnormally, all messages up to the point of - termination are output. -

16.1.2.2.2. maxsize (integer)

- Only relevant when destination is file, this is maximum - file size of output files in bytes. When the maximum - size is reached, the file is renamed and a new file opened. - (For example, a ".1" is appended to the name — - if a ".1" file exists, it is renamed ".2", - etc.) -

- If this is 0, no maximum file size is used. -

16.1.2.2.3. maxver (integer)

- Maximum number of old log files to keep around when - rolling the output file. Only relevant when - destination is file. -

16.1.3. Example session

- - In this example we want to set the global logging to - write to the file /var/log/my_bind10.log, - at severity WARN. We want the authoritative server to - log at DEBUG with debuglevel 40, to a different file - (/tmp/debug_messages). - -

- - Start bindctl. - -

- -

["login success "]
-> config show Logging
-Logging/loggers	[]	list
-

- -

- - By default, no specific loggers are configured, in which - case the severity defaults to INFO and the output is - written to stderr. - -

- - Let's first add a default logger: - -

- -

> config add Logging/loggers
-> config show Logging
-Logging/loggers/	list	(modified)
-

- -

- - The loggers value line changed to indicate that it is no - longer an empty list: - -

- -

> config show Logging/loggers
-Logging/loggers[0]/name	""	string	(default)
-Logging/loggers[0]/severity	"INFO"	string	(default)
-Logging/loggers[0]/debuglevel	0	integer	(default)
-Logging/loggers[0]/additive	false	boolean	(default)
-Logging/loggers[0]/output_options	[]	list	(default)
-

- -

- - The name is mandatory, so we must set it. We will also - change the severity as well. Let's start with the global - logger. - -

- -

> config set Logging/loggers[0]/name *
-> config set Logging/loggers[0]/severity WARN
-> config show Logging/loggers
-Logging/loggers[0]/name	"*"	string	(modified)
-Logging/loggers[0]/severity	"WARN"	string	(modified)
-Logging/loggers[0]/debuglevel	0	integer	(default)
-Logging/loggers[0]/additive	false	boolean	(default)
-Logging/loggers[0]/output_options	[]	list	(default)
-

- -

- - Of course, we need to specify where we want the log - messages to go, so we add an entry for an output option. - -

- -

>  config add Logging/loggers[0]/output_options
->  config show Logging/loggers[0]/output_options
-Logging/loggers[0]/output_options[0]/destination	"console"	string	(default)
-Logging/loggers[0]/output_options[0]/output	"stdout"	string	(default)
-Logging/loggers[0]/output_options[0]/flush	false	boolean	(default)
-Logging/loggers[0]/output_options[0]/maxsize	0	integer	(default)
-Logging/loggers[0]/output_options[0]/maxver	0	integer	(default)
-

- - -

- - These aren't the values we are looking for. - -

- -

>  config set Logging/loggers[0]/output_options[0]/destination file
->  config set Logging/loggers[0]/output_options[0]/output /var/log/bind10.log
->  config set Logging/loggers[0]/output_options[0]/maxsize 30000
->  config set Logging/loggers[0]/output_options[0]/maxver 8
-

- -

- - Which would make the entire configuration for this logger - look like: - -

- -

>  config show all Logging/loggers
-Logging/loggers[0]/name	"*"	string	(modified)
-Logging/loggers[0]/severity	"WARN"	string	(modified)
-Logging/loggers[0]/debuglevel	0	integer	(default)
-Logging/loggers[0]/additive	false	boolean	(default)
-Logging/loggers[0]/output_options[0]/destination	"file"	string	(modified)
-Logging/loggers[0]/output_options[0]/output	"/var/log/bind10.log"	string	(modified)
-Logging/loggers[0]/output_options[0]/flush	false	boolean	(default)
-Logging/loggers[0]/output_options[0]/maxsize	30000	integer	(modified)
-Logging/loggers[0]/output_options[0]/maxver	8	integer	(modified)
-

- -

- - That looks OK, so let's commit it before we add the - configuration for the authoritative server's logger. - -

- -

>  config commit

- -

- - Now that we have set it, and checked each value along - the way, adding a second entry is quite similar. - -

- -

>  config add Logging/loggers
->  config set Logging/loggers[1]/name Auth
->  config set Logging/loggers[1]/severity DEBUG
->  config set Logging/loggers[1]/debuglevel 40
->  config add Logging/loggers[1]/output_options
->  config set Logging/loggers[1]/output_options[0]/destination file
->  config set Logging/loggers[1]/output_options[0]/output /tmp/auth_debug.log
->  config commit
-

- -

- - And that's it. Once we have found whatever it was we - needed the debug messages for, we can simply remove the - second logger to let the authoritative server use the - same settings as the rest. - -

- -

>  config remove Logging/loggers[1]
->  config commit
-

- -

- - And every module will now be using the values from the - logger named *. - -

16.2. Logging Message Format

- Each message written by BIND 10 to the configured logging - destinations comprises a number of components that identify - the origin of the message and, if the message indicates - a problem, information about the problem that may be - useful in fixing it. -

- Consider the message below logged to a file: -

2011-06-15 13:48:22.034 ERROR [b10-resolver.asiolink]
-    ASIODNS_OPENSOCK error 111 opening TCP socket to 127.0.0.1(53)

-

- Note: the layout of messages written to the system logging - file (syslog) may be slightly different. This message has - been split across two lines here for display reasons; in the - logging file, it will appear on one line.) -

- The log message comprises a number of components: - -

2011-06-15 13:48:22.034

- The date and time at which the message was generated. -

ERROR

- The severity of the message. -

[b10-resolver.asiolink]

- The source of the message. This comprises two components: - the BIND 10 process generating the message (in this - case, b10-resolver) and the module - within the program from which the message originated - (which in the example is the asynchronous I/O link - module, asiolink). -

ASIODNS_OPENSOCK

- The message identification. Every message in BIND 10 - has a unique identification, which can be used as an - index into the BIND 10 Messages - Manual (http://bind10.isc.org/docs/bind10-messages.html) from which more information can be obtained. -

error 111 opening TCP socket to 127.0.0.1(53)

- A brief description of the cause of the problem. - Within this text, information relating to the condition - that caused the message to be logged will be included. - In this example, error number 111 (an operating - system-specific error number) was encountered when - trying to open a TCP connection to port 53 on the - local system (address 127.0.0.1). The next step - would be to find out the reason for the failure by - consulting your system's documentation to identify - what error number 111 means. -

-

diff --git a/doc/guide/bind10-guide.txt b/doc/guide/bind10-guide.txt deleted file mode 100644 index 7ec35e6da7..0000000000 --- a/doc/guide/bind10-guide.txt +++ /dev/null @@ -1,1726 +0,0 @@ - BIND 10 Guide - -Administrator Reference for BIND 10 - - This is the reference guide for BIND 10 version 20120127. - - Copyright (c) 2010-2012 Internet Systems Consortium, Inc. - - Abstract - - BIND 10 is a framework that features Domain Name System (DNS) suite and - Dynamic Host Configuration Protocol (DHCP) servers managed by Internet - Systems Consortium (ISC). It includes DNS libraries, modular components - for controlling authoritative and recursive DNS servers, and experimental - DHCPv4 and DHCPv6 servers. - - This is the reference guide for BIND 10 version 20120127. The most - up-to-date version of this document (in PDF, HTML, and plain text - formats), along with other documents for BIND 10, can be found at - http://bind10.isc.org/docs. - - -------------------------------------------------------------------------- - - Table of Contents - - Preface - - 1. Acknowledgements - - 1. Introduction - - 1.1. Supported Platforms - - 1.2. Required Software - - 1.3. Starting and Stopping the Server - - 1.4. Managing BIND 10 - - 2. Installation - - 2.1. Building Requirements - - 2.2. Quick start - - 2.3. Installation from source - - 2.3.1. Download Tar File - - 2.3.2. Retrieve from Git - - 2.3.3. Configure before the build - - 2.3.4. Build - - 2.3.5. Install - - 2.3.6. Install Hierarchy - - 3. Starting BIND10 with bind10 - - 3.1. Starting BIND 10 - - 3.2. Configuration of started processes - - 4. Command channel - - 5. Configuration manager - - 6. Remote control daemon - - 6.1. Configuration specification for b10-cmdctl - - 7. Control and configure user interface - - 8. Authoritative Server - - 8.1. Server Configurations - - 8.2. Data Source Backends - - 8.3. Loading Master Zones Files - - 9. Incoming Zone Transfers - - 9.1. Configuration for Incoming Zone Transfers - - 9.2. Enabling IXFR - - 9.3. Secondary Manager - - 9.4. Trigger an Incoming Zone Transfer Manually - - 10. Outbound Zone Transfers - - 11. Recursive Name Server - - 11.1. Access Control - - 11.2. Forwarding - - 12. DHCPv4 Server - - 12.1. DHCPv4 Server Usage - - 12.2. DHCPv4 Server Configuration - - 12.3. Supported standards - - 12.4. DHCPv4 Server Limitations - - 13. DHCPv6 Server - - 13.1. DHCPv6 Server Usage - - 13.2. DHCPv6 Server Configuration - - 13.3. Supported DHCPv6 Standards - - 13.4. DHCPv6 Server Limitations - - 14. libdhcp++ library - - 14.1. Interface detection - - 14.2. DHCPv4/DHCPv6 packet handling - - 15. Statistics - - 16. Logging - - 16.1. Logging configuration - - 16.1.1. Loggers - - 16.1.2. Output Options - - 16.1.3. Example session - - 16.2. Logging Message Format - - List of Tables - - 3.1. - -Preface - - Table of Contents - - 1. Acknowledgements - -1. Acknowledgements - - ISC would like to acknowledge generous support for BIND 10 development of - DHCPv4 and DHCPv6 components provided by Comcast. - -Chapter 1. Introduction - - Table of Contents - - 1.1. Supported Platforms - - 1.2. Required Software - - 1.3. Starting and Stopping the Server - - 1.4. Managing BIND 10 - - BIND is the popular implementation of a DNS server, developer interfaces, - and DNS tools. BIND 10 is a rewrite of BIND 9. BIND 10 is written in C++ - and Python and provides a modular environment for serving and maintaining - DNS. BIND 10 provides a EDNS0- and DNSSEC-capable authoritative DNS server - and a caching recursive name server which also provides forwarding. - - This guide covers the experimental prototype of BIND 10 version 20120127. - -1.1. Supported Platforms - - BIND 10 builds have been tested on Debian GNU/Linux 5 and unstable, Ubuntu - 9.10, NetBSD 5, Solaris 10, FreeBSD 7 and 8, CentOS Linux 5.3, and MacOS - 10.6. It has been tested on Sparc, i386, and amd64 hardware platforms. It - is planned for BIND 10 to build, install and run on Windows and standard - Unix-type platforms. - -1.2. Required Software - - BIND 10 requires at least Python 3.1 (http://www.python.org/). It has also - been tested with Python 3.2. - - BIND 10 uses the Botan crypto library for C++ - (http://botan.randombit.net/). It requires at least Botan version 1.8. - - BIND 10 uses the log4cplus C++ logging library - (http://log4cplus.sourceforge.net/). It requires at least log4cplus - version 1.0.3. - - The authoritative DNS server uses SQLite3 (http://www.sqlite.org/). It - needs at least SQLite version 3.3.9. - - The b10-xfrin, b10-xfrout, and b10-zonemgr components require the - libpython3 library and the Python _sqlite3.so module (which is included - with Python). The Python module needs to be built for the corresponding - Python 3. - - Note - - Some operating systems do not provide these dependencies in their default - installation nor standard packages collections. You may need to install - them separately. - -1.3. Starting and Stopping the Server - - BIND 10 is modular. Part of this modularity is accomplished using multiple - cooperating processes which, together, provide the server functionality. - This is a change from the previous generation of BIND software, which used - a single process. - - At first, running many different processes may seem confusing. However, - these processes are started, stopped, and maintained by a single command, - bind10. This command starts a master process which will start other - processes as needed. The processes started by the bind10 command have - names starting with "b10-", including: - - o b10-msgq -- Message bus daemon. This process coordinates communication - between all of the other BIND 10 processes. - o b10-auth -- Authoritative DNS server. This process serves DNS - requests. - o b10-cfgmgr -- Configuration manager. This process maintains all of the - configuration for BIND 10. - o b10-cmdctl -- Command and control service. This process allows - external control of the BIND 10 system. - o b10-resolver -- Recursive name server. This process handles incoming - queries. - o b10-stats -- Statistics collection daemon. This process collects and - reports statistics data. - o b10-xfrin -- Incoming zone transfer service. This process is used to - transfer a new copy of a zone into BIND 10, when acting as a secondary - server. - o b10-xfrout -- Outgoing zone transfer service. This process is used to - handle transfer requests to send a local zone to a remote secondary - server, when acting as a master server. - o b10-zonemgr -- Secondary manager. This process keeps track of timers - and other necessary information for BIND 10 to act as a slave server. - - These are ran automatically by bind10 and do not need to be run manually. - -1.4. Managing BIND 10 - - Once BIND 10 is running, a few commands are used to interact directly with - the system: - - o bindctl -- interactive administration interface. This is a - command-line tool which allows an administrator to control BIND 10. - o b10-loadzone -- zone file loader. This tool will load standard - masterfile-format zone files into BIND 10. - o b10-cmdctl-usermgr -- user access control. This tool allows an - administrator to authorize additional users to manage BIND 10. - - The tools and modules are covered in full detail in this guide. In - addition, manual pages are also provided in the default installation. - - BIND 10 also provides libraries and programmer interfaces for C++ and - Python for the message bus, configuration backend, and, of course, DNS. - These include detailed developer documentation and code examples. - -Chapter 2. Installation - - Table of Contents - - 2.1. Building Requirements - - 2.2. Quick start - - 2.3. Installation from source - - 2.3.1. Download Tar File - - 2.3.2. Retrieve from Git - - 2.3.3. Configure before the build - - 2.3.4. Build - - 2.3.5. Install - - 2.3.6. Install Hierarchy - -2.1. Building Requirements - - In addition to the run-time requirements, building BIND 10 from source - code requires various development include headers. - - Note - - Some operating systems have split their distribution packages into a - run-time and a development package. You will need to install the - development package versions, which include header files and libraries, to - build BIND 10 from source code. - - Building from source code requires the Boost build-time headers - (http://www.boost.org/). At least Boost version 1.35 is required. - - To build BIND 10, also install the Botan (at least version 1.8) and the - log4cplus (at least version 1.0.3) development include headers. - - Building BIND 10 also requires a C++ compiler and standard development - headers, make, and pkg-config. BIND 10 builds have been tested with GCC - g++ 3.4.3, 4.1.2, 4.1.3, 4.2.1, 4.3.2, and 4.4.1; Clang++ 2.8; and Sun C++ - 5.10. - - Visit the wiki at http://bind10.isc.org/wiki/SystemSpecificNotes for - system-specific installation tips. - -2.2. Quick start - - Note - - This quickly covers the standard steps for installing and deploying BIND - 10 as an authoritative name server using its defaults. For - troubleshooting, full customizations and further details, see the - respective chapters in the BIND 10 guide. - - To quickly get started with BIND 10, follow these steps. - - 1. Install required run-time and build dependencies. - 2. Download the BIND 10 source tar file from - ftp://ftp.isc.org/isc/bind10/. - 3. Extract the tar file: - - $ gzcat bind10-VERSION.tar.gz | tar -xvf - - - 4. Go into the source and run configure: - - $ cd bind10-VERSION - $ ./configure - - 5. Build it: - - $ make - - 6. Install it (to default /usr/local): - - $ make install - - 7. Start the server: - - $ /usr/local/sbin/bind10 - - 8. Test it; for example: - - $ dig @127.0.0.1 -c CH -t TXT authors.bind - - 9. Load desired zone file(s), for example: - - $ b10-loadzone your.zone.example.org - - 10. Test the new zone. - -2.3. Installation from source - - BIND 10 is open source software written in C++ and Python. It is freely - available in source code form from ISC via the Git code revision control - system or as a downloadable tar file. It may also be available in - pre-compiled ready-to-use packages from operating system vendors. - - 2.3.1. Download Tar File - - Downloading a release tar file is the recommended method to obtain the - source code. - - The BIND 10 releases are available as tar file downloads from - ftp://ftp.isc.org/isc/bind10/. Periodic development snapshots may also be - available. - - 2.3.2. Retrieve from Git - - Downloading this "bleeding edge" code is recommended only for developers - or advanced users. Using development code in a production environment is - not recommended. - - Note - - When using source code retrieved via Git additional software will be - required: automake (v1.11 or newer), libtoolize, and autoconf (2.59 or - newer). These may need to be installed. - - The latest development code, including temporary experiments and - un-reviewed code, is available via the BIND 10 code revision control - system. This is powered by Git and all the BIND 10 development is public. - The leading development is done in the "master". - - The code can be checked out from git://git.bind10.isc.org/bind10; for - example: - - $ git clone git://git.bind10.isc.org/bind10 - - When checking out the code from the code version control system, it - doesn't include the generated configure script, Makefile.in files, nor the - related configure files. They can be created by running autoreconf with - the --install switch. This will run autoconf, aclocal, libtoolize, - autoheader, automake, and related commands. - - 2.3.3. Configure before the build - - BIND 10 uses the GNU Build System to discover build environment details. - To generate the makefiles using the defaults, simply run: - - $ ./configure - - Run ./configure with the --help switch to view the different options. The - commonly-used options are: - - --prefix - Define the installation location (the default is /usr/local/). - - --with-boost-include - Define the path to find the Boost headers. - - --with-pythonpath - Define the path to Python 3.1 if it is not in the standard - execution path. - - --with-gtest - Enable building the C++ Unit Tests using the Google Tests - framework. Optionally this can define the path to the gtest header - files and library. - - For example, the following configures it to find the Boost headers, find - the Python interpreter, and sets the installation location: - - $ ./configure \ - --with-boost-include=/usr/pkg/include \ - --with-pythonpath=/usr/pkg/bin/python3.1 \ - --prefix=/opt/bind10 - - If the configure fails, it may be due to missing or old dependencies. - - 2.3.4. Build - - After the configure step is complete, to build the executables from the - C++ code and prepare the Python scripts, run: - - $ make - - 2.3.5. Install - - To install the BIND 10 executables, support files, and documentation, run: - - $ make install - - Note - - The install step may require superuser privileges. - - 2.3.6. Install Hierarchy - - The following is the layout of the complete BIND 10 installation: - - o bin/ -- general tools and diagnostic clients. - o etc/bind10-devel/ -- configuration files. - o lib/ -- libraries and python modules. - o libexec/bind10-devel/ -- executables that a user wouldn't normally run - directly and are not run independently. These are the BIND 10 modules - which are daemons started by the bind10 tool. - o sbin/ -- commands used by the system administrator. - o share/bind10-devel/ -- configuration specifications. - o share/man/ -- manual pages (online documentation). - o var/bind10-devel/ -- data source and configuration databases. - -Chapter 3. Starting BIND10 with bind10 - - Table of Contents - - 3.1. Starting BIND 10 - - 3.2. Configuration of started processes - - BIND 10 provides the bind10 command which starts up the required - processes. bind10 will also restart some processes that exit unexpectedly. - This is the only command needed to start the BIND 10 system. - - After starting the b10-msgq communications channel, bind10 connects to it, - runs the configuration manager, and reads its own configuration. Then it - starts the other modules. - - The b10-sockcreator, b10-msgq and b10-cfgmgr services make up the core. - The b10-msgq daemon provides the communication channel between every part - of the system. The b10-cfgmgr daemon is always needed by every module, if - only to send information about themselves somewhere, but more importantly - to ask about their own settings, and about other modules. The - b10-sockcreator will allocate sockets for the rest of the system. - - In its default configuration, the bind10 master process will also start up - b10-cmdctl for admins to communicate with the system, b10-auth for - authoritative DNS service, b10-stats for statistics collection, b10-xfrin - for inbound DNS zone transfers, b10-xfrout for outbound DNS zone - transfers, and b10-zonemgr for secondary service. - -3.1. Starting BIND 10 - - To start the BIND 10 service, simply run bind10. Run it with the --verbose - switch to get additional debugging or diagnostic output. - - Note - - If the setproctitle Python module is detected at start up, the process - names for the Python-based daemons will be renamed to better identify them - instead of just "python". This is not needed on some operating systems. - -3.2. Configuration of started processes - - The processes to be started can be configured, with the exception of the - b10-sockcreator, b10-msgq and b10-cfgmgr. - - The configuration is in the Boss/components section. Each element - represents one component, which is an abstraction of a process (currently - there's also one component which doesn't represent a process). If you - didn't want to transfer out at all (your server is a slave only), you - would just remove the corresponding component from the set, like this and - the process would be stopped immediately (and not started on the next - startup): - - > config remove Boss/components b10-xfrout - > config commit - - To add a process to the set, let's say the resolver (which not started by - default), you would do this: - - > config add Boss/components b10-resolver - > config set Boss/components/b10-resolver/special resolver - > config set Boss/components/b10-resolver/kind needed - > config set Boss/components/b10-resolver/priority 10 - > config commit - - Now, what it means. We add an entry called b10-resolver. It is both a name - used to reference this component in the configuration and the name of the - process to start. Then we set some parameters on how to start it. - - The special one is for components that need some kind of special care - during startup or shutdown. Unless specified, the component is started in - usual way. This is the list of components that need to be started in a - special way, with the value of special used for them: - - Table 3.1. - - +------------------------------------------------------------------------+ - | Component | Special | Description | - |--------------+----------+----------------------------------------------| - | b10-auth | auth | Authoritative server | - |--------------+----------+----------------------------------------------| - | b10-resolver | resolver | The resolver | - |--------------+----------+----------------------------------------------| - | b10-cmdctl | cmdctl | The command control (remote control | - | | | interface) | - +------------------------------------------------------------------------+ - - The kind specifies how a failure of the component should be handled. If it - is set to "dispensable" (the default unless you set something else), it - will get started again if it fails. If it is set to "needed" and it fails - at startup, the whole bind10 shuts down and exits with error exit code. - But if it fails some time later, it is just started again. If you set it - to "core", you indicate that the system is not usable without the - component and if such component fails, the system shuts down no matter - when the failure happened. This is the behaviour of the core components - (the ones you can't turn off), but you can declare any other components as - core as well if you wish (but you can turn these off, they just can't - fail). - - The priority defines order in which the components should start. The ones - with higher number are started sooner than the ones with lower ones. If - you don't set it, 0 (zero) is used as the priority. Usually, leaving it at - the default is enough. - - There are other parameters we didn't use in our example. One of them is - "address". It is the address used by the component on the b10-msgq message - bus. The special components already know their address, but the usual ones - don't. The address is by convention the thing after b10-, with the first - letter capital (eg. b10-stats would have "Stats" as its address). - - The last one is process. It is the name of the process to be started. It - defaults to the name of the component if not set, but you can use this to - override it. - - Note - - This system allows you to start the same component multiple times (by - including it in the configuration with different names, but the same - process setting). However, the rest of the system doesn't expect such - situation, so it would probably not do what you want. Such support is yet - to be implemented. - - Note - - The configuration is quite powerful, but that includes a lot of space for - mistakes. You could turn off the b10-cmdctl, but then you couldn't change - it back the usual way, as it would require it to be running (you would - have to find and edit the configuration directly). Also, some modules - might have dependencies -- b10-stats-httpd need b10-stats, b10-xfrout - needs the b10-auth to be running, etc. - - In short, you should think twice before disabling something here. - -Chapter 4. Command channel - - The BIND 10 components use the b10-msgq message routing daemon to - communicate with other BIND 10 components. The b10-msgq implements what is - called the "Command Channel". Processes intercommunicate by sending - messages on the command channel. Example messages include shutdown, get - configurations, and set configurations. This Command Channel is not used - for DNS message passing. It is used only to control and monitor the BIND - 10 system. - - Administrators do not communicate directly with the b10-msgq daemon. By - default, BIND 10 uses port 9912 for the b10-msgq service. It listens on - 127.0.0.1. - -Chapter 5. Configuration manager - - The configuration manager, b10-cfgmgr, handles all BIND 10 system - configuration. It provides persistent storage for configuration, and - notifies running modules of configuration changes. - - The b10-auth and b10-xfrin daemons and other components receive their - configurations from the configuration manager over the b10-msgq command - channel. - - The administrator doesn't connect to it directly, but uses a user - interface to communicate with the configuration manager via b10-cmdctl's - REST-ful interface. b10-cmdctl is covered in Chapter 6, Remote control - daemon. - - Note - - The development prototype release only provides the bindctl as a user - interface to b10-cmdctl. Upcoming releases will provide another - interactive command-line interface and a web-based interface. - - The b10-cfgmgr daemon can send all specifications and all current settings - to the bindctl client (via b10-cmdctl). - - b10-cfgmgr relays configurations received from b10-cmdctl to the - appropriate modules. - - The stored configuration file is at - /usr/local/var/bind10-devel/b10-config.db. (The full path is what was - defined at build configure time for --localstatedir. The default is - /usr/local/var/.) The format is loosely based on JSON and is directly - parseable python, but this may change in a future version. This - configuration data file is not manually edited by the administrator. - - The configuration manager does not have any command line arguments. - Normally it is not started manually, but is automatically started using - the bind10 master process (as covered in Chapter 3, Starting BIND10 with - bind10). - -Chapter 6. Remote control daemon - - Table of Contents - - 6.1. Configuration specification for b10-cmdctl - - b10-cmdctl is the gateway between administrators and the BIND 10 system. - It is a HTTPS server that uses standard HTTP Digest Authentication for - username and password validation. It provides a REST-ful interface for - accessing and controlling BIND 10. - - When b10-cmdctl starts, it firsts asks b10-cfgmgr about what modules are - running and what their configuration is (over the b10-msgq channel). Then - it will start listening on HTTPS for clients -- the user interface -- such - as bindctl. - - b10-cmdctl directly sends commands (received from the user interface) to - the specified component. Configuration changes are actually commands to - b10-cfgmgr so are sent there. - - The HTTPS server requires a private key, such as a RSA PRIVATE KEY. The - default location is at /usr/local/etc/bind10-devel/cmdctl-keyfile.pem. (A - sample key is at /usr/local/share/bind10-devel/cmdctl-keyfile.pem.) It - also uses a certificate located at - /usr/local/etc/bind10-devel/cmdctl-certfile.pem. (A sample certificate is - at /usr/local/share/bind10-devel/cmdctl-certfile.pem.) This may be a - self-signed certificate or purchased from a certification authority. - - Note - - The HTTPS server doesn't support a certificate request from a client (at - this time). The b10-cmdctl daemon does not provide a public service. If - any client wants to control BIND 10, then a certificate needs to be first - received from the BIND 10 administrator. The BIND 10 installation provides - a sample PEM bundle that matches the sample key and certificate. - - The b10-cmdctl daemon also requires the user account file located at - /usr/local/etc/bind10-devel/cmdctl-accounts.csv. This comma-delimited file - lists the accounts with a user name, hashed password, and salt. (A sample - file is at /usr/local/share/bind10-devel/cmdctl-accounts.csv. It contains - the user named "root" with the password "bind10".) - - The administrator may create a user account with the b10-cmdctl-usermgr - tool. - - By default the HTTPS server listens on the localhost port 8080. The port - can be set by using the --port command line option. The address to listen - on can be set using the --address command line argument. Each HTTPS - connection is stateless and timesout in 1200 seconds by default. This can - be redefined by using the --idle-timeout command line argument. - -6.1. Configuration specification for b10-cmdctl - - The configuration items for b10-cmdctl are: key_file cert_file - accounts_file - - The control commands are: print_settings shutdown - -Chapter 7. Control and configure user interface - - Note - - For this development prototype release, bindctl is the only user - interface. It is expected that upcoming releases will provide another - interactive command-line interface and a web-based interface for - controlling and configuring BIND 10. - - The bindctl tool provides an interactive prompt for configuring, - controlling, and querying the BIND 10 components. It communicates directly - with a REST-ful interface over HTTPS provided by b10-cmdctl. It doesn't - communicate to any other components directly. - - Configuration changes are actually commands to b10-cfgmgr. So when bindctl - sends a configuration, it is sent to b10-cmdctl (over a HTTPS connection); - then b10-cmdctl sends the command (over a b10-msgq command channel) to - b10-cfgmgr which then stores the details and relays (over a b10-msgq - command channel) the configuration on to the specified module. - -Chapter 8. Authoritative Server - - Table of Contents - - 8.1. Server Configurations - - 8.2. Data Source Backends - - 8.3. Loading Master Zones Files - - The b10-auth is the authoritative DNS server. It supports EDNS0 and - DNSSEC. It supports IPv6. Normally it is started by the bind10 master - process. - -8.1. Server Configurations - - b10-auth is configured via the b10-cfgmgr configuration manager. The - module name is "Auth". The configuration data item is: - - database_file - This is an optional string to define the path to find the SQLite3 - database file. Note: Later the DNS server will use various data - source backends. This may be a temporary setting until then. - - The configuration command is: - - shutdown - Stop the authoritative DNS server. - -8.2. Data Source Backends - - Note - - For the development prototype release, b10-auth supports a SQLite3 data - source backend and in-memory data source backend. Upcoming versions will - be able to use multiple different data sources, such as MySQL and Berkeley - DB. - - By default, the SQLite3 backend uses the data file located at - /usr/local/var/bind10-devel/zone.sqlite3. (The full path is what was - defined at build configure time for --localstatedir. The default is - /usr/local/var/.) This data file location may be changed by defining the - "database_file" configuration. - -8.3. Loading Master Zones Files - - RFC 1035 style DNS master zone files may imported into a BIND 10 data - source by using the b10-loadzone utility. - - b10-loadzone supports the following special directives (control entries): - - $INCLUDE - Loads an additional zone file. This may be recursive. - - $ORIGIN - Defines the relative domain name. - - $TTL - Defines the time-to-live value used for following records that - don't include a TTL. - - The -o argument may be used to define the default origin for loaded zone - file records. - - Note - - In the development prototype release, only the SQLite3 back end is used. - By default, it stores the zone data in - /usr/local/var/bind10-devel/zone.sqlite3 unless the -d switch is used to - set the database filename. Multiple zones are stored in a single SQLite3 - zone database. - - If you reload a zone already existing in the database, all records from - that prior zone disappear and a whole new set appears. - -Chapter 9. Incoming Zone Transfers - - Table of Contents - - 9.1. Configuration for Incoming Zone Transfers - - 9.2. Enabling IXFR - - 9.3. Secondary Manager - - 9.4. Trigger an Incoming Zone Transfer Manually - - Incoming zones are transferred using the b10-xfrin process which is - started by bind10. When received, the zone is stored in the corresponding - BIND 10 data source, and its records can be served by b10-auth. In - combination with b10-zonemgr (for automated SOA checks), this allows the - BIND 10 server to provide "secondary" service. - - The b10-xfrin process supports both AXFR and IXFR. Due to some - implementation limitations of the current development release, however, it - only tries AXFR by default, and care should be taken to enable IXFR. - - Note - - In the current development release of BIND 10, incoming zone transfers are - only available for SQLite3-based data sources, that is, they don't work - for an in-memory data source. - -9.1. Configuration for Incoming Zone Transfers - - In practice, you need to specify a list of secondary zones to enable - incoming zone transfers for these zones (you can still trigger a zone - transfer manually, without a prior configuration (see below)). - - For example, to enable zone transfers for a zone named "example.com" - (whose master address is assumed to be 2001:db8::53 here), run the - following at the bindctl prompt: - - > config add Xfrin/zones - > config set Xfrin/zones[0]/name "example.com" - > config set Xfrin/zones[0]/master_addr "2001:db8::53" - > config commit - - (We assume there has been no zone configuration before). - -9.2. Enabling IXFR - - As noted above, b10-xfrin uses AXFR for zone transfers by default. To - enable IXFR for zone transfers for a particular zone, set the use_ixfr - configuration parameter to true. In the above example of configuration - sequence, you'll need to add the following before performing commit: - - > config set Xfrin/zones[0]/use_ixfr true - - Note - - One reason why IXFR is disabled by default in the current release is - because it does not support automatic fallback from IXFR to AXFR when it - encounters a primary server that doesn't support outbound IXFR (and, not - many existing implementations support it). Another, related reason is that - it does not use AXFR even if it has no knowledge about the zone (like at - the very first time the secondary server is set up). IXFR requires the - "current version" of the zone, so obviously it doesn't work in this - situation and AXFR is the only workable choice. The current release of - b10-xfrin does not make this selection automatically. These features will - be implemented in a near future version, at which point we will enable - IXFR by default. - -9.3. Secondary Manager - - The b10-zonemgr process is started by bind10. It keeps track of SOA - refresh, retry, and expire timers and other details for BIND 10 to perform - as a slave. When the b10-auth authoritative DNS server receives a NOTIFY - message, b10-zonemgr may tell b10-xfrin to do a refresh to start an - inbound zone transfer. The secondary manager resets its counters when a - new zone is transferred in. - - Note - - Access control (such as allowing notifies) is not yet provided. The - primary/secondary service is not yet complete. - - The following example shows using bindctl to configure the server to be a - secondary for the example zone: - - > config add Zonemgr/secondary_zones - > config set Zonemgr/secondary_zones[0]/name "example.com" - > config set Zonemgr/secondary_zones[0]/class "IN" - > config commit - - If the zone does not exist in the data source already (i.e. no SOA record - for it), b10-zonemgr will automatically tell b10-xfrin to transfer the - zone in. - -9.4. Trigger an Incoming Zone Transfer Manually - - To manually trigger a zone transfer to retrieve a remote zone, you may use - the bindctl utility. For example, at the bindctl prompt run: - - > Xfrin retransfer zone_name="foo.example.org" master=192.0.2.99 - -Chapter 10. Outbound Zone Transfers - - The b10-xfrout process is started by bind10. When the b10-auth - authoritative DNS server receives an AXFR or IXFR request, b10-auth - internally forwards the request to b10-xfrout, which handles the rest of - request processing. This is used to provide primary DNS service to share - zones to secondary name servers. The b10-xfrout is also used to send - NOTIFY messages to secondary servers. - - A global or per zone transfer_acl configuration can be used to control - accessibility of the outbound zone transfer service. By default, - b10-xfrout allows any clients to perform zone transfers for any zones: - - > config show Xfrout/transfer_acl - Xfrout/transfer_acl[0] {"action": "ACCEPT"} any (default) - - You can change this to, for example, rejecting all transfer requests by - default while allowing requests for the transfer of zone "example.com" - from 192.0.2.1 and 2001:db8::1 as follows: - - > config set Xfrout/transfer_acl[0] {"action": "REJECT"} - > config add Xfrout/zone_config - > config set Xfrout/zone_config[0]/origin "example.com" - > config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1"}, - {"action": "ACCEPT", "from": "2001:db8::1"}] - > config commit - - Note - - In the above example the lines for transfer_acl were divided for - readability. In the actual input it must be in a single line. - - If you want to require TSIG in access control, a separate TSIG "key ring" - must be configured specifically for b10-xfrout as well as a system wide - key ring, both containing a consistent set of keys. For example, to change - the previous example to allowing requests from 192.0.2.1 signed by a TSIG - with a key name of "key.example", you'll need to do this: - - > config set tsig_keys/keys ["key.example:"] - > config set Xfrout/tsig_keys/keys ["key.example:"] - > config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1", "key": "key.example"}] - > config commit - - The first line of configuration defines a system wide key ring. This is - necessary because the b10-auth server also checks TSIGs and it uses the - system wide configuration. - - Note - - In a future version, b10-xfrout will also use the system wide TSIG - configuration. The way to specify zone specific configuration (ACLs, etc) - is likely to be changed, too. - -Chapter 11. Recursive Name Server - - Table of Contents - - 11.1. Access Control - - 11.2. Forwarding - - The b10-resolver process is started by bind10. - - The main bind10 process can be configured to select to run either the - authoritative or resolver or both. By default, it starts the authoritative - service. You may change this using bindctl, for example: - - > config remove Boss/components b10-xfrout - > config remove Boss/components b10-xfrin - > config remove Boss/components b10-auth - > config add Boss/components b10-resolver - > config set Boss/components/b10-resolver/special resolver - > config set Boss/components/b10-resolver/kind needed - > config set Boss/components/b10-resolver/priority 10 - > config commit - - The master bind10 will stop and start the desired services. - - By default, the resolver listens on port 53 for 127.0.0.1 and ::1. The - following example shows how it can be configured to listen on an - additional address (and port): - - > config add Resolver/listen_on - > config set Resolver/listen_on[2]/address "192.168.1.1" - > config set Resolver/listen_on[2]/port 53 - > config commit - - (Replace the "2" as needed; run "config show Resolver/listen_on" if - needed.) - -11.1. Access Control - - By default, the b10-resolver daemon only accepts DNS queries from the - localhost (127.0.0.1 and ::1). The Resolver/query_acl configuration may be - used to reject, drop, or allow specific IPs or networks. This - configuration list is first match. - - The configuration's action item may be set to "ACCEPT" to allow the - incoming query, "REJECT" to respond with a DNS REFUSED return code, or - "DROP" to ignore the query without any response (such as a blackhole). For - more information, see the respective debugging messages: - RESOLVER_QUERY_ACCEPTED, RESOLVER_QUERY_REJECTED, and - RESOLVER_QUERY_DROPPED. - - The required configuration's from item is set to an IPv4 or IPv6 address, - addresses with an network mask, or to the special lowercase keywords - "any6" (for any IPv6 address) or "any4" (for any IPv4 address). - - For example to allow the 192.168.1.0/24 network to use your recursive name - server, at the bindctl prompt run: - - > config add Resolver/query_acl - > config set Resolver/query_acl[2]/action "ACCEPT" - > config set Resolver/query_acl[2]/from "192.168.1.0/24" - > config commit - - (Replace the "2" as needed; run "config show Resolver/query_acl" if - needed.) - - Note - - This prototype access control configuration syntax may be changed. - -11.2. Forwarding - - To enable forwarding, the upstream address and port must be configured to - forward queries to, such as: - - > config set Resolver/forward_addresses [{ "address": "192.168.1.1", "port": 53 }] - > config commit - - (Replace 192.168.1.1 to point to your full resolver.) - - Normal iterative name service can be re-enabled by clearing the forwarding - address(es); for example: - - > config set Resolver/forward_addresses [] - > config commit - -Chapter 12. DHCPv4 Server - - Table of Contents - - 12.1. DHCPv4 Server Usage - - 12.2. DHCPv4 Server Configuration - - 12.3. Supported standards - - 12.4. DHCPv4 Server Limitations - - Dynamic Host Configuration Protocol for IPv4 (DHCP or DHCPv4) and Dynamic - Host Configuration Protocol for IPv6 (DHCPv6) are protocols that allow one - node (server) to provision configuration parameters to many hosts and - devices (clients). To ease deployment in larger networks, additional nodes - (relays) may be deployed that facilitate communication between servers and - clients. Even though principles of both DHCPv4 and DHCPv6 are somewhat - similar, these are two radically different protocols. BIND10 offers server - implementations for both DHCPv4 and DHCPv6. This chapter is about DHCP for - IPv4. For a description of the DHCPv6 server, see Chapter 13, DHCPv6 - Server. - - The DHCPv4 server component is currently under intense development. You - may want to check out BIND10 DHCP (Kea) wiki and recent posts on BIND10 - developers mailing list. - - The DHCPv4 and DHCPv6 components in BIND10 architecture are internally - code named "Kea". - - Note - - As of December 2011, both DHCPv4 and DHCPv6 components are skeleton - servers. That means that while they are capable of performing DHCP - configuration, they are not fully functional yet. In particular, neither - has functional lease databases. This means that they will assign the same, - fixed, hardcoded addresses to any client that will ask. See Section 12.4, - "DHCPv4 Server Limitations" and Section 13.4, "DHCPv6 Server Limitations" - for detailed description. - -12.1. DHCPv4 Server Usage - - BIND10 provides the DHCPv4 server component since December 2011. It is a - skeleton server and can be described as an early prototype that is not - fully functional yet. It is mature enough to conduct first tests in lab - environment, but it has significant limitations. See Section 12.4, "DHCPv4 - Server Limitations" for details. - - The DHCPv4 server is implemented as b10-dhcp4 daemon. As it is not - configurable yet, it is fully autonomous, that is it does not interact - with b10-cfgmgr. To start DHCPv4 server, simply input: - - #cd src/bin/dhcp4 - #./b10-dhcp4 - - Depending on your installation, b10-dhcp4 binary may reside in - src/bin/dhcp4 in your source code directory, in /usr/local/bin/b10-dhcp4 - or other directory you specified during compilation. At start, the server - will detect available network interfaces and will attempt to open UDP - sockets on all interfaces that are up, running, are not loopback, and have - IPv4 address assigned. The server will then listen to incoming traffic. - Currently supported client messages are DISCOVER and REQUEST. The server - will respond to them with OFFER and ACK, respectively. Since the DHCPv4 - server opens privileged ports, it requires root access. Make sure you run - this daemon as root. - - Note - - Integration with bind10 is planned. Ultimately, b10-dhcp4 will not be - started directly, but rather via bind10. Please be aware of this planned - change. - -12.2. DHCPv4 Server Configuration - - The DHCPv4 server does not have a lease database implemented yet nor any - support for configuration, so every time the same set of configuration - options (including the same fixed address) will be assigned every time. - - At this stage of development, the only way to alter the server - configuration is to tweak its source code. To do so, please edit - src/bin/dhcp4/dhcp4_srv.cc file and modify following parameters and - recompile: - - const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease - const std::string HARDCODED_NETMASK = "255.255.255.0"; - const uint32_t HARDCODED_LEASE_TIME = 60; // in seconds - const std::string HARDCODED_GATEWAY = "192.0.2.1"; - const std::string HARDCODED_DNS_SERVER = "192.0.2.2"; - const std::string HARDCODED_DOMAIN_NAME = "isc.example.com"; - const std::string HARDCODED_SERVER_ID = "192.0.2.1"; - - Lease database and configuration support is planned for 2012. - -12.3. Supported standards - - The following standards and draft standards are currently supported: - - o RFC2131: Supported messages are DISCOVER, OFFER, REQUEST, and ACK. - o RFC2132: Supported options are: PAD (0), END(255), Message Type(53), - DHCP Server Identifier (54), Domain Name (15), DNS Servers (6), IP - Address Lease Time (51), Subnet mask (1), and Routers (3). - -12.4. DHCPv4 Server Limitations - - These are the current limitations of the DHCPv4 server software. Most of - them are reflections of the early stage of development and should be - treated as "not implemented yet", rather than actual limitations. - - o During initial IPv4 node configuration, the server is expected to send - packets to a node that does not have IPv4 address assigned yet. The - server requires certain tricks (or hacks) to transmit such packets. - This is not implemented yet, therefore DHCPv4 server supports relayed - traffic only (that is, normal point to point communication). - o b10-dhcp4 provides a single, fixed, hardcoded lease to any client that - asks. There is no lease manager implemented. If two clients request - addresses, they will both get the same fixed address. - o b10-dhcp4 does not support any configuration mechanisms yet. The whole - configuration is currently hardcoded. The only way to tweak - configuration is to directly modify source code. See see Section 12.2, - "DHCPv4 Server Configuration" for details. - o Upon start, the server will open sockets on all interfaces that are - not loopback, are up and running and have IPv4 address. Support for - multiple interfaces is not coded in reception routines yet, so if you - are running this code on a machine that has many interfaces and - b10-dhcp4 happens to listen on wrong interface, the easiest way to - work around this problem is to turn down other interfaces. This - limitation will be fixed shortly. - o PRL (Parameter Request List, a list of options requested by a client) - is currently ignored and server assigns DNS SERVER and DOMAIN NAME - options. - o b10-dhcp4 does not support BOOTP. That is a design choice. This - limitation is permanent. If you have legacy nodes that can't use DHCP - and require BOOTP support, please use latest version of ISC DHCP - http://www.isc.org/software/dhcp. - o Interface detection is currently working on Linux only. See - Section 14.1, "Interface detection" for details. - o b10-dhcp4 does not verify that assigned address is unused. According - to RFC2131, the allocating server should verify that address is no - used by sending ICMP echo request. - o Address renewal (RENEW), rebinding (REBIND), confirmation (CONFIRM), - duplication report (DECLINE) and release (RELEASE) are not supported - yet. - o DNS Update is not supported yet. - o -v (verbose) command line option is currently the default, and cannot - be disabled. - -Chapter 13. DHCPv6 Server - - Table of Contents - - 13.1. DHCPv6 Server Usage - - 13.2. DHCPv6 Server Configuration - - 13.3. Supported DHCPv6 Standards - - 13.4. DHCPv6 Server Limitations - - Dynamic Host Configuration Protocol for IPv6 (DHCPv6) is specified in - RFC3315. BIND10 provides DHCPv6 server implementation that is described in - this chapter. For a description of the DHCPv4 server implementation, see - Chapter 12, DHCPv4 Server. - - The DHCPv6 server component is currently under intense development. You - may want to check out BIND10 DHCP (Kea) wiki and recent posts on BIND10 - developers mailing list. - - The DHCPv4 and DHCPv6 components in BIND10 architecture are internally - code named "Kea". - - Note - - As of December 2011, both DHCPv4 and DHCPv6 components are skeleton - servers. That means that while they are capable of performing DHCP - configuration, they are not fully functional yet. In particular, neither - has functional lease databases. This means that they will assign the same, - fixed, hardcoded addresses to any client that will ask. See Section 12.4, - "DHCPv4 Server Limitations" and Section 13.4, "DHCPv6 Server Limitations" - for detailed description. - -13.1. DHCPv6 Server Usage - - BIND10 provides the DHCPv6 server component since September 2011. It is a - skeleton server and can be described as an early prototype that is not - fully functional yet. It is mature enough to conduct first tests in lab - environment, but it has significant limitations. See Section 13.4, "DHCPv6 - Server Limitations" for details. - - The DHCPv6 server is implemented as b10-dhcp6 daemon. As it is not - configurable yet, it is fully autonomous, that is it does not interact - with b10-cfgmgr. To start DHCPv6 server, simply input: - - #cd src/bin/dhcp6 - #./b10-dhcp6 - - Depending on your installation, b10-dhcp6 binary may reside in - src/bin/dhcp6 in your source code directory, in /usr/local/bin/b10-dhcp6 - or other directory you specified during compilation. At start, server will - detect available network interfaces and will attempt to open UDP sockets - on all interfaces that are up, running, are not loopback, are - multicast-capable, and have IPv6 address assigned. The server will then - listen to incoming traffic. Currently supported client messages are - SOLICIT and REQUEST. The server will respond to them with ADVERTISE and - REPLY, respectively. Since the DHCPv6 server opens privileged ports, it - requires root access. Make sure you run this daemon as root. - - Note - - Integration with bind10 is planned. Ultimately, b10-dhcp6 will not be - started directly, but rather via bind10. Please be aware of this planned - change. - -13.2. DHCPv6 Server Configuration - - The DHCPv6 server does not have lease database implemented yet or any - support for configuration, so every time the same set of configuration - options (including the same fixed address) will be assigned every time. - - At this stage of development, the only way to alter server configuration - is to tweak its source code. To do so, please edit - src/bin/dhcp6/dhcp6_srv.cc file and modify following parameters and - recompile: - - const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd"; - const uint32_t HARDCODED_T1 = 1500; // in seconds - const uint32_t HARDCODED_T2 = 2600; // in seconds - const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds - const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds - const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1"; - - Lease database and configuration support is planned for 2012. - -13.3. Supported DHCPv6 Standards - - The following standards and draft standards are currently supported: - - o RFC3315: Supported messages are SOLICIT, ADVERTISE, REQUEST, and - REPLY. Supported options are SERVER_ID, CLIENT_ID, IA_NA, and - IAADDRESS. - o RFC3646: Supported option is DNS_SERVERS. - -13.4. DHCPv6 Server Limitations - - These are the current limitations of the DHCPv6 server software. Most of - them are reflections of the early stage of development and should be - treated as "not implemented yet", rather than actual limitations. - - o Relayed traffic is not supported. - o b10-dhcp6 provides a single, fixed, hardcoded lease to any client that - asks. There is no lease manager implemented. If two clients request - addresses, they will both get the same fixed address. - o b10-dhcp6 does not support any configuration mechanisms yet. The whole - configuration is currently hardcoded. The only way to tweak - configuration is to directly modify source code. See see Section 13.2, - "DHCPv6 Server Configuration" for details. - o Upon start, the server will open sockets on all interfaces that are - not loopback, are up, running and are multicast capable and have IPv6 - address. Support for multiple interfaces is not coded in reception - routines yet, so if you are running this code on a machine that has - many interfaces and b10-dhcp6 happens to listen on wrong interface, - the easiest way to work around this problem is to turn down other - interfaces. This limitation will be fixed shortly. - o ORO (Option Request Option, a list of options requested by a client) - is currently ignored and server assigns DNS SERVER option. - o Temporary addresses are not supported yet. - o Prefix delegation is not supported yet. - o Address renewal (RENEW), rebinding (REBIND), confirmation (CONFIRM), - duplication report (DECLINE) and release (RELEASE) are not supported - yet. - o DNS Update is not supported yet. - o Interface detection is currently working on Linux only. See - Section 14.1, "Interface detection" for details. - o -v (verbose) command line option is currently the default, and cannot - be disabled. - -Chapter 14. libdhcp++ library - - Table of Contents - - 14.1. Interface detection - - 14.2. DHCPv4/DHCPv6 packet handling - - libdhcp++ is a common library written in C++ that handles many - DHCP-related tasks, like DHCPv4 and DHCPv6 packets parsing, manipulation - and assembly, option parsing, manipulation and assembly, network interface - detection and socket operations, like socket creations, data transmission - and reception and socket closing. - - While this library is currently used by b10-dhcp4 and b10-dhcp6 only, it - is designed to be portable, universal library useful for any kind of - DHCP-related software. - -14.1. Interface detection - - Both DHCPv4 and DHCPv6 components share network interface detection - routines. Interface detection is currently only supported on Linux - systems. - - For non-Linux systems, there is currently stub implementation provided. As - DHCP servers need to know available addresses, there is a simple mechanism - implemented to provide that information. User is expected to create - interfaces.txt file. Format of this file is simple. It contains list of - interfaces along with available address on each interface. This mechanism - is temporary and is going to be removed as soon as interface detection - becomes available on non-Linux systems. Here is an example of the - interfaces.txt file: - - # For DHCPv6, please specify link-local address (starts with fe80::) - # If in doubt, check output of 'ifconfig -a' command. - eth0 fe80::21e:8cff:fe9b:7349 - - # For DHCPv4, please use following format: - #eth0 192.0.2.5 - -14.2. DHCPv4/DHCPv6 packet handling - - TODO: Describe packet handling here, with pointers to wiki - -Chapter 15. Statistics - - The b10-stats process is started by bind10. It periodically collects - statistics data from various modules and aggregates it. - - This stats daemon provides commands to identify if it is running, show - specified or all statistics data, show specified or all statistics data - schema, and set specified statistics data. For example, using bindctl: - - > Stats show - { - "Auth": { - "opcode.iquery": 0, - "opcode.notify": 10, - "opcode.query": 869617, - ... - "queries.tcp": 1749, - "queries.udp": 867868 - }, - "Boss": { - "boot_time": "2011-01-20T16:59:03Z" - }, - "Stats": { - "boot_time": "2011-01-20T16:59:05Z", - "last_update_time": "2011-01-20T17:04:05Z", - "lname": "4d3869d9_a@jreed.example.net", - "report_time": "2011-01-20T17:04:06Z", - "timestamp": 1295543046.823504 - } - } - - -Chapter 16. Logging - - Table of Contents - - 16.1. Logging configuration - - 16.1.1. Loggers - - 16.1.2. Output Options - - 16.1.3. Example session - - 16.2. Logging Message Format - -16.1. Logging configuration - - The logging system in BIND 10 is configured through the Logging module. - All BIND 10 modules will look at the configuration in Logging to see what - should be logged and to where. - - 16.1.1. Loggers - - Within BIND 10, a message is logged through a component called a "logger". - Different parts of BIND 10 log messages through different loggers, and - each logger can be configured independently of one another. - - In the Logging module, you can specify the configuration for zero or more - loggers; any that are not specified will take appropriate default values.. - - The three most important elements of a logger configuration are the name - (the component that is generating the messages), the severity (what to - log), and the output_options (where to log). - - 16.1.1.1. name (string) - - Each logger in the system has a name, the name being that of the component - using it to log messages. For instance, if you want to configure logging - for the resolver module, you add an entry for a logger named "Resolver". - This configuration will then be used by the loggers in the Resolver - module, and all the libraries used by it. - - If you want to specify logging for one specific library within the module, - you set the name to module.library. For example, the logger used by the - nameserver address store component has the full name of "Resolver.nsas". - If there is no entry in Logging for a particular library, it will use the - configuration given for the module. - - To illustrate this, suppose you want the cache library to log messages of - severity DEBUG, and the rest of the resolver code to log messages of - severity INFO. To achieve this you specify two loggers, one with the name - "Resolver" and severity INFO, and one with the name "Resolver.cache" with - severity DEBUG. As there are no entries for other libraries (e.g. the - nsas), they will use the configuration for the module ("Resolver"), so - giving the desired behavior. - - One special case is that of a module name of "*" (asterisks), which is - interpreted as any module. You can set global logging options by using - this, including setting the logging configuration for a library that is - used by multiple modules (e.g. "*.config" specifies the configuration - library code in whatever module is using it). - - If there are multiple logger specifications in the configuration that - might match a particular logger, the specification with the more specific - logger name takes precedence. For example, if there are entries for for - both "*" and "Resolver", the resolver module -- and all libraries it uses - -- will log messages according to the configuration in the second entry - ("Resolver"). All other modules will use the configuration of the first - entry ("*"). If there was also a configuration entry for "Resolver.cache", - the cache library within the resolver would use that in preference to the - entry for "Resolver". - - One final note about the naming. When specifying the module name within a - logger, use the name of the module as specified in bindctl, e.g. - "Resolver" for the resolver module, "Xfrout" for the xfrout module, etc. - When the message is logged, the message will include the name of the - logger generating the message, but with the module name replaced by the - name of the process implementing the module (so for example, a message - generated by the "Auth.cache" logger will appear in the output with a - logger name of "b10-auth.cache"). - - 16.1.1.2. severity (string) - - This specifies the category of messages logged. Each message is logged - with an associated severity which may be one of the following (in - descending order of severity): - - o FATAL - o ERROR - o WARN - o INFO - o DEBUG - - When the severity of a logger is set to one of these values, it will only - log messages of that severity, and the severities above it. The severity - may also be set to NONE, in which case all messages from that logger are - inhibited. - - 16.1.1.3. output_options (list) - - Each logger can have zero or more output_options. These specify where log - messages are sent to. These are explained in detail below. - - The other options for a logger are: - - 16.1.1.4. debuglevel (integer) - - When a logger's severity is set to DEBUG, this value specifies what debug - messages should be printed. It ranges from 0 (least verbose) to 99 (most - verbose). - - If severity for the logger is not DEBUG, this value is ignored. - - 16.1.1.5. additive (true or false) - - If this is true, the output_options from the parent will be used. For - example, if there are two loggers configured; "Resolver" and - "Resolver.cache", and additive is true in the second, it will write the - log messages not only to the destinations specified for "Resolver.cache", - but also to the destinations as specified in the output_options in the - logger named "Resolver". - - 16.1.2. Output Options - - The main settings for an output option are the destination and a value - called output, the meaning of which depends on the destination that is - set. - - 16.1.2.1. destination (string) - - The destination is the type of output. It can be one of: - - o console - o file - o syslog - - 16.1.2.2. output (string) - - Depending on what is set as the output destination, this value is - interpreted as follows: - - destination is "console" - The value of output must be one of "stdout" (messages printed to - standard output) or "stderr" (messages printed to standard error). - - destination is "file" - The value of output is interpreted as a file name; log messages - will be appended to this file. - - destination is "syslog" - The value of output is interpreted as the syslog facility (e.g. - local0) that should be used for log messages. - - The other options for output_options are: - - 16.1.2.2.1. flush (true of false) - - Flush buffers after each log message. Doing this will reduce performance - but will ensure that if the program terminates abnormally, all messages up - to the point of termination are output. - - 16.1.2.2.2. maxsize (integer) - - Only relevant when destination is file, this is maximum file size of - output files in bytes. When the maximum size is reached, the file is - renamed and a new file opened. (For example, a ".1" is appended to the - name -- if a ".1" file exists, it is renamed ".2", etc.) - - If this is 0, no maximum file size is used. - - 16.1.2.2.3. maxver (integer) - - Maximum number of old log files to keep around when rolling the output - file. Only relevant when destination is "file". - - 16.1.3. Example session - - In this example we want to set the global logging to write to the file - /var/log/my_bind10.log, at severity WARN. We want the authoritative server - to log at DEBUG with debuglevel 40, to a different file - (/tmp/debug_messages). - - Start bindctl. - - ["login success "] - > config show Logging - Logging/loggers [] list - - By default, no specific loggers are configured, in which case the severity - defaults to INFO and the output is written to stderr. - - Let's first add a default logger: - - > config add Logging/loggers - > config show Logging - Logging/loggers/ list (modified) - - The loggers value line changed to indicate that it is no longer an empty - list: - - > config show Logging/loggers - Logging/loggers[0]/name "" string (default) - Logging/loggers[0]/severity "INFO" string (default) - Logging/loggers[0]/debuglevel 0 integer (default) - Logging/loggers[0]/additive false boolean (default) - Logging/loggers[0]/output_options [] list (default) - - The name is mandatory, so we must set it. We will also change the severity - as well. Let's start with the global logger. - - > config set Logging/loggers[0]/name * - > config set Logging/loggers[0]/severity WARN - > config show Logging/loggers - Logging/loggers[0]/name "*" string (modified) - Logging/loggers[0]/severity "WARN" string (modified) - Logging/loggers[0]/debuglevel 0 integer (default) - Logging/loggers[0]/additive false boolean (default) - Logging/loggers[0]/output_options [] list (default) - - Of course, we need to specify where we want the log messages to go, so we - add an entry for an output option. - - > config add Logging/loggers[0]/output_options - > config show Logging/loggers[0]/output_options - Logging/loggers[0]/output_options[0]/destination "console" string (default) - Logging/loggers[0]/output_options[0]/output "stdout" string (default) - Logging/loggers[0]/output_options[0]/flush false boolean (default) - Logging/loggers[0]/output_options[0]/maxsize 0 integer (default) - Logging/loggers[0]/output_options[0]/maxver 0 integer (default) - - These aren't the values we are looking for. - - > config set Logging/loggers[0]/output_options[0]/destination file - > config set Logging/loggers[0]/output_options[0]/output /var/log/bind10.log - > config set Logging/loggers[0]/output_options[0]/maxsize 30000 - > config set Logging/loggers[0]/output_options[0]/maxver 8 - - Which would make the entire configuration for this logger look like: - - > config show all Logging/loggers - Logging/loggers[0]/name "*" string (modified) - Logging/loggers[0]/severity "WARN" string (modified) - Logging/loggers[0]/debuglevel 0 integer (default) - Logging/loggers[0]/additive false boolean (default) - Logging/loggers[0]/output_options[0]/destination "file" string (modified) - Logging/loggers[0]/output_options[0]/output "/var/log/bind10.log" string (modified) - Logging/loggers[0]/output_options[0]/flush false boolean (default) - Logging/loggers[0]/output_options[0]/maxsize 30000 integer (modified) - Logging/loggers[0]/output_options[0]/maxver 8 integer (modified) - - That looks OK, so let's commit it before we add the configuration for the - authoritative server's logger. - - > config commit - - Now that we have set it, and checked each value along the way, adding a - second entry is quite similar. - - > config add Logging/loggers - > config set Logging/loggers[1]/name Auth - > config set Logging/loggers[1]/severity DEBUG - > config set Logging/loggers[1]/debuglevel 40 - > config add Logging/loggers[1]/output_options - > config set Logging/loggers[1]/output_options[0]/destination file - > config set Logging/loggers[1]/output_options[0]/output /tmp/auth_debug.log - > config commit - - And that's it. Once we have found whatever it was we needed the debug - messages for, we can simply remove the second logger to let the - authoritative server use the same settings as the rest. - - > config remove Logging/loggers[1] - > config commit - - And every module will now be using the values from the logger named "*". - -16.2. Logging Message Format - - Each message written by BIND 10 to the configured logging destinations - comprises a number of components that identify the origin of the message - and, if the message indicates a problem, information about the problem - that may be useful in fixing it. - - Consider the message below logged to a file: - - 2011-06-15 13:48:22.034 ERROR [b10-resolver.asiolink] - ASIODNS_OPENSOCK error 111 opening TCP socket to 127.0.0.1(53) - - Note: the layout of messages written to the system logging file (syslog) - may be slightly different. This message has been split across two lines - here for display reasons; in the logging file, it will appear on one - line.) - - The log message comprises a number of components: - - 2011-06-15 13:48:22.034 - - The date and time at which the message was generated. - - ERROR - - The severity of the message. - - [b10-resolver.asiolink] - - The source of the message. This comprises two components: the BIND - 10 process generating the message (in this case, b10-resolver) and - the module within the program from which the message originated - (which in the example is the asynchronous I/O link module, - asiolink). - - ASIODNS_OPENSOCK - - The message identification. Every message in BIND 10 has a unique - identification, which can be used as an index into the BIND 10 - Messages Manual (http://bind10.isc.org/docs/bind10-messages.html) - from which more information can be obtained. - - error 111 opening TCP socket to 127.0.0.1(53) - - A brief description of the cause of the problem. Within this text, - information relating to the condition that caused the message to - be logged will be included. In this example, error number 111 (an - operating system-specific error number) was encountered when - trying to open a TCP connection to port 53 on the local system - (address 127.0.0.1). The next step would be to find out the reason - for the failure by consulting your system's documentation to - identify what error number 111 means. diff --git a/doc/guide/bind10-messages.html b/doc/guide/bind10-messages.html deleted file mode 100644 index b82b485603..0000000000 --- a/doc/guide/bind10-messages.html +++ /dev/null @@ -1,2628 +0,0 @@ -BIND 10 Messages Manual

BIND 10 Messages Manual

This is the messages manual for BIND 10 version - 20111129.

Abstract

BIND 10 is a Domain Name System (DNS) suite managed by - Internet Systems Consortium (ISC). It includes DNS libraries - and modular components for controlling authoritative and - recursive DNS servers. -

- This is the messages manual for BIND 10 version 20111129. - The most up-to-date version of this document, along with - other documents for BIND 10, can be found at - http://bind10.isc.org/docs. -


Chapter 1. Introduction

- This document lists each message that can be logged by the - programs in the BIND 10 package. Each entry in this manual - is of the form: -

IDENTIFICATION message-text

- ... where "IDENTIFICATION" is the message identification included - in each message logged and "message-text" is the accompanying - message text. The "message-text" may include placeholders of the - form "%1", "%2" etc.; these parameters are replaced by relevant - values when the message is logged. -

- Each entry is also accompanied by a description giving more - information about the circumstances that result in the message - being logged. -

- For information on configuring and using BIND 10 logging, - refer to the BIND 10 Guide. -

Chapter 2. BIND 10 Messages

-

ASIODNS_FD_ADD_TCP adding a new TCP server by opened fd %1

-A debug message informing about installing a file descriptor as a server. -The file descriptor number is noted. -

ASIODNS_FD_ADD_UDP adding a new UDP server by opened fd %1

-A debug message informing about installing a file descriptor as a server. -The file descriptor number is noted. -

ASIODNS_FETCH_COMPLETED upstream fetch to %1(%2) has now completed

-A debug message, this records that the upstream fetch (a query made by the -resolver on behalf of its client) to the specified address has completed. -

ASIODNS_FETCH_STOPPED upstream fetch to %1(%2) has been stopped

-An external component has requested the halting of an upstream fetch. This -is an allowed operation, and the message should only appear if debug is -enabled. -

ASIODNS_OPEN_SOCKET error %1 opening %2 socket to %3(%4)

-The asynchronous I/O code encountered an error when trying to open a socket -of the specified protocol in order to send a message to the target address. -The number of the system error that caused the problem is given in the -message. -

ASIODNS_READ_DATA error %1 reading %2 data from %3(%4)

-The asynchronous I/O code encountered an error when trying to read data from -the specified address on the given protocol. The number of the system -error that caused the problem is given in the message. -

ASIODNS_READ_TIMEOUT receive timeout while waiting for data from %1(%2)

-An upstream fetch from the specified address timed out. This may happen for -any number of reasons and is most probably a problem at the remote server -or a problem on the network. The message will only appear if debug is -enabled. -

ASIODNS_SEND_DATA error %1 sending data using %2 to %3(%4)

-The asynchronous I/O code encountered an error when trying to send data to -the specified address on the given protocol. The number of the system -error that caused the problem is given in the message. -

ASIODNS_UNKNOWN_ORIGIN unknown origin for ASIO error code %1 (protocol: %2, address %3)

-An internal consistency check on the origin of a message from the -asynchronous I/O module failed. This may indicate an internal error; -please submit a bug report. -

ASIODNS_UNKNOWN_RESULT unknown result (%1) when IOFetch::stop() was executed for I/O to %2(%3)

-An internal error indicating that the termination method of the resolver's -upstream fetch class was called with an unknown result code (which is -given in the message). Please submit a bug report. -

AUTH_AXFR_ERROR error handling AXFR request: %1

-This is a debug message produced by the authoritative server when it -has encountered an error processing an AXFR request. The message gives -the reason for the error, and the server will return a SERVFAIL code to -the sender. -

AUTH_AXFR_UDP AXFR query received over UDP

-This is a debug message output when the authoritative server has received -an AXFR query over UDP. Use of UDP for AXFRs is not permitted by the -protocol, so the server will return a FORMERR error to the sender. -

AUTH_COMMAND_FAILED execution of command channel instruction '%1' failed: %2

-Execution of the specified command by the authoritative server failed. The -message contains the reason for the failure. -

AUTH_CONFIG_CHANNEL_CREATED configuration session channel created

-This is a debug message indicating that authoritative server has created -the channel to the configuration manager. It is issued during server -startup is an indication that the initialization is proceeding normally. -

AUTH_CONFIG_CHANNEL_ESTABLISHED configuration session channel established

-This is a debug message indicating that authoritative server -has established communication the configuration manager over the -previously-created channel. It is issued during server startup is an -indication that the initialization is proceeding normally. -

AUTH_CONFIG_CHANNEL_STARTED configuration session channel started

-This is a debug message, issued when the authoritative server has -posted a request to be notified when new configuration information is -available. It is issued during server startup is an indication that -the initialization is proceeding normally. -

AUTH_CONFIG_LOAD_FAIL load of configuration failed: %1

-An attempt to configure the server with information from the configuration -database during the startup sequence has failed. (The reason for -the failure is given in the message.) The server will continue its -initialization although it may not be configured in the desired way. -

AUTH_CONFIG_UPDATE_FAIL update of configuration failed: %1

-At attempt to update the configuration the server with information -from the configuration database has failed, the reason being given in -the message. -

AUTH_DATA_SOURCE data source database file: %1

-This is a debug message produced by the authoritative server when it accesses a -datebase data source, listing the file that is being accessed. -

AUTH_DNS_SERVICES_CREATED DNS services created

-This is a debug message indicating that the component that will handling -incoming queries for the authoritative server (DNSServices) has been -successfully created. It is issued during server startup is an indication -that the initialization is proceeding normally. -

AUTH_HEADER_PARSE_FAIL unable to parse header in received DNS packet: %1

-This is a debug message, generated by the authoritative server when an -attempt to parse the header of a received DNS packet has failed. (The -reason for the failure is given in the message.) The server will drop the -packet. -

AUTH_INVALID_STATISTICS_DATA invalid specification of statistics data specified

-An error was encountered when the authoritiative server specified -statistics data which is invalid for the auth specification file. -

AUTH_LOAD_TSIG loading TSIG keys

-This is a debug message indicating that the authoritative server -has requested the keyring holding TSIG keys from the configuration -database. It is issued during server startup is an indication that the -initialization is proceeding normally. -

AUTH_LOAD_ZONE loaded zone %1/%2

-This debug message is issued during the processing of the 'loadzone' command -when the authoritative server has successfully loaded the named zone of the -named class. -

AUTH_MEM_DATASRC_DISABLED memory data source is disabled for class %1

-This is a debug message reporting that the authoritative server has -discovered that the memory data source is disabled for the given class. -

AUTH_MEM_DATASRC_ENABLED memory data source is enabled for class %1

-This is a debug message reporting that the authoritative server has -discovered that the memory data source is enabled for the given class. -

AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY

-This debug message is logged by the authoritative server when it receives -a NOTIFY packet that contains zero or more than one question. (A valid -NOTIFY packet contains one question.) The server will return a FORMERR -error to the sender. -

AUTH_NOTIFY_RRTYPE invalid question RR type (%1) in incoming NOTIFY

-This debug message is logged by the authoritative server when it receives -a NOTIFY packet that an RR type of something other than SOA in the -question section. (The RR type received is included in the message.) The -server will return a FORMERR error to the sender. -

AUTH_NO_STATS_SESSION session interface for statistics is not available

-The authoritative server had no session with the statistics module at the -time it attempted to send it data: the attempt has been abandoned. This -could be an error in configuration. -

AUTH_NO_XFRIN received NOTIFY but XFRIN session is not running

-This is a debug message produced by the authoritative server when it receives -a NOTIFY packet but the XFRIN process is not running. The packet will be -dropped and nothing returned to the sender. -

AUTH_PACKET_PARSE_ERROR unable to parse received DNS packet: %1

-This is a debug message, generated by the authoritative server when an -attempt to parse a received DNS packet has failed due to something other -than a protocol error. The reason for the failure is given in the message; -the server will return a SERVFAIL error code to the sender. -

AUTH_PACKET_PROTOCOL_ERROR DNS packet protocol error: %1. Returning %2

-This is a debug message, generated by the authoritative server when an -attempt to parse a received DNS packet has failed due to a protocol error. -The reason for the failure is given in the message, as is the error code -that will be returned to the sender. -

AUTH_PACKET_RECEIVED message received:\n%1

-This is a debug message output by the authoritative server when it -receives a valid DNS packet. -

-Note: This message includes the packet received, rendered in the form of -multiple lines of text. For this reason, it is suggested that this log message -not be routed to the syslog file, where the multiple lines could confuse -programs that expect a format of one message per line. -

AUTH_PROCESS_FAIL message processing failure: %1

-This message is generated by the authoritative server when it has -encountered an internal error whilst processing a received packet: -the cause of the error is included in the message. -

-The server will return a SERVFAIL error code to the sender of the packet. -This message indicates a potential error in the server. Please open a -bug ticket for this issue. -

AUTH_RECEIVED_COMMAND command '%1' received

-This is a debug message issued when the authoritative server has received -a command on the command channel. -

AUTH_RECEIVED_SENDSTATS command 'sendstats' received

-This is a debug message issued when the authoritative server has received -a command from the statistics module to send it data. The 'sendstats' -command is handled differently to other commands, which is why the debug -message associated with it has its own code. -

AUTH_RESPONSE_RECEIVED received response message, ignoring

-This is a debug message, this is output if the authoritative server -receives a DNS packet with the QR bit set, i.e. a DNS response. The -server ignores the packet as it only responds to question packets. -

AUTH_SEND_ERROR_RESPONSE sending an error response (%1 bytes):\n%2

-This is a debug message recording that the authoritative server is sending -an error response to the originator of the query. A previous message will -have recorded details of the failure. -

-Note: This message includes the packet sent, rendered in the form of -multiple lines of text. For this reason, it is suggested that this log message -not be routed to the syslog file, where the multiple lines could confuse -programs that expect a format of one message per line. -

AUTH_SEND_NORMAL_RESPONSE sending an error response (%1 bytes):\n%2

-This is a debug message recording that the authoritative server is sending -a response to the originator of a query. -

-Note: This message includes the packet sent, rendered in the form of -multiple lines of text. For this reason, it is suggested that this log message -not be routed to the syslog file, where the multiple lines could confuse -programs that expect a format of one message per line. -

AUTH_SERVER_CREATED server created

-An informational message indicating that the authoritative server process has -been created and is initializing. The AUTH_SERVER_STARTED message will be -output when initialization has successfully completed and the server starts -accepting queries. -

AUTH_SERVER_FAILED server failed: %1

-The authoritative server has encountered a fatal error and is terminating. The -reason for the failure is included in the message. -

AUTH_SERVER_STARTED server started

-Initialization of the authoritative server has completed successfully -and it is entering the main loop, waiting for queries to arrive. -

AUTH_SQLITE3 nothing to do for loading sqlite3

-This is a debug message indicating that the authoritative server has -found that the data source it is loading is an SQLite3 data source, -so no further validation is needed. -

AUTH_STATS_CHANNEL_CREATED STATS session channel created

-This is a debug message indicating that the authoritative server has -created a channel to the statistics process. It is issued during server -startup is an indication that the initialization is proceeding normally. -

AUTH_STATS_CHANNEL_ESTABLISHED STATS session channel established

-This is a debug message indicating that the authoritative server -has established communication over the previously created statistics -channel. It is issued during server startup is an indication that the -initialization is proceeding normally. -

AUTH_STATS_COMMS communication error in sending statistics data: %1

-An error was encountered when the authoritative server tried to send data -to the statistics daemon. The message includes additional information -describing the reason for the failure. -

AUTH_STATS_TIMEOUT timeout while sending statistics data: %1

-The authoritative server sent data to the statistics daemon but received -no acknowledgement within the specified time. The message includes -additional information describing the reason for the failure. -

AUTH_STATS_TIMER_DISABLED statistics timer has been disabled

-This is a debug message indicating that the statistics timer has been -disabled in the authoritative server and no statistics information is -being produced. -

AUTH_STATS_TIMER_SET statistics timer set to %1 second(s)

-This is a debug message indicating that the statistics timer has been -enabled and that the authoritative server will produce statistics data -at the specified interval. -

AUTH_UNSUPPORTED_OPCODE unsupported opcode: %1

-This is a debug message, produced when a received DNS packet being -processed by the authoritative server has been found to contain an -unsupported opcode. (The opcode is included in the message.) The server -will return an error code of NOTIMPL to the sender. -

AUTH_XFRIN_CHANNEL_CREATED XFRIN session channel created

-This is a debug message indicating that the authoritative server has -created a channel to the XFRIN (Transfer-in) process. It is issued -during server startup is an indication that the initialization is -proceeding normally. -

AUTH_XFRIN_CHANNEL_ESTABLISHED XFRIN session channel established

-This is a debug message indicating that the authoritative server has -established communication over the previously-created channel to the -XFRIN (Transfer-in) process. It is issued during server startup is an -indication that the initialization is proceeding normally. -

AUTH_ZONEMGR_COMMS error communicating with zone manager: %1

-This is a debug message output during the processing of a NOTIFY request. -An error (listed in the message) has been encountered whilst communicating -with the zone manager. The NOTIFY request will not be honored. -

AUTH_ZONEMGR_ERROR received error response from zone manager: %1

-This is a debug message output during the processing of a NOTIFY -request. The zone manager component has been informed of the request, -but has returned an error response (which is included in the message). The -NOTIFY request will not be honored. -

BIND10_CHECK_MSGQ_ALREADY_RUNNING checking if msgq is already running

-The boss process is starting up and will now check if the message bus -daemon is already running. If so, it will not be able to start, as it -needs a dedicated message bus. -

BIND10_COMPONENT_FAILED component %1 (pid %2) failed with %3 exit status

-The process terminated, but the bind10 boss didn't expect it to, which means -it must have failed. -

BIND10_COMPONENT_RESTART component %1 is about to restart

-The named component failed previously and we will try to restart it to provide -as flawless service as possible, but it should be investigated what happened, -as it could happen again. -

BIND10_COMPONENT_START component %1 is starting

-The named component is about to be started by the boss process. -

BIND10_COMPONENT_START_EXCEPTION component %1 failed to start: %2

-An exception (mentioned in the message) happened during the startup of the -named component. The componet is not considered started and further actions -will be taken about it. -

BIND10_COMPONENT_STOP component %1 is being stopped

-A component is about to be asked to stop willingly by the boss. -

BIND10_COMPONENT_UNSATISFIED component %1 is required to run and failed

-A component failed for some reason (see previous messages). It is either a core -component or needed component that was just started. In any case, the system -can't continue without it and will terminate. -

BIND10_CONFIGURATOR_BUILD building plan '%1' -> '%2'

-A debug message. This indicates that the configurator is building a plan -how to change configuration from the older one to newer one. This does no -real work yet, it just does the planning what needs to be done. -

BIND10_CONFIGURATOR_PLAN_INTERRUPTED configurator plan interrupted, only %1 of %2 done

-There was an exception during some planned task. The plan will not continue and -only some tasks of the plan were completed. The rest is aborted. The exception -will be propagated. -

BIND10_CONFIGURATOR_RECONFIGURE reconfiguring running components

-A different configuration of which components should be running is being -installed. All components that are no longer needed will be stopped and -newly introduced ones started. This happens at startup, when the configuration -is read the first time, or when an operator changes configuration of the boss. -

BIND10_CONFIGURATOR_RUN running plan of %1 tasks

-A debug message. The configurator is about to execute a plan of actions it -computed previously. -

BIND10_CONFIGURATOR_START bind10 component configurator is starting up

-The part that cares about starting and stopping the right component from the -boss process is starting up. This happens only once at the startup of the -boss process. It will start the basic set of processes now (the ones boss -needs to read the configuration), the rest will be started after the -configuration is known. -

BIND10_CONFIGURATOR_STOP bind10 component configurator is shutting down

-The part that cares about starting and stopping processes in the boss is -shutting down. All started components will be shut down now (more precisely, -asked to terminate by their own, if they fail to comply, other parts of -the boss process will try to force them). -

BIND10_CONFIGURATOR_TASK performing task %1 on %2

-A debug message. The configurator is about to perform one task of the plan it -is currently executing on the named component. -

BIND10_INVALID_STATISTICS_DATA invalid specification of statistics data specified

-An error was encountered when the boss module specified -statistics data which is invalid for the boss specification file. -

BIND10_INVALID_USER invalid user: %1

-The boss process was started with the -u option, to drop root privileges -and continue running as the specified user, but the user is unknown. -

BIND10_KILLING_ALL_PROCESSES killing all started processes

-The boss module was not able to start every process it needed to start -during startup, and will now kill the processes that did get started. -

BIND10_KILL_PROCESS killing process %1

-The boss module is sending a kill signal to process with the given name, -as part of the process of killing all started processes during a failed -startup, as described for BIND10_KILLING_ALL_PROCESSES -

BIND10_LOST_SOCKET_CONSUMER consumer %1 of sockets disconnected, considering all its sockets closed

-A connection from one of the applications which requested a socket was -closed. This means the application has terminated, so all the sockets it was -using are now closed and bind10 process can release them as well, unless the -same sockets are used by yet another application. -

BIND10_MSGQ_ALREADY_RUNNING msgq daemon already running, cannot start

-There already appears to be a message bus daemon running. Either an -old process was not shut down correctly, and needs to be killed, or -another instance of BIND10, with the same msgq domain socket, is -running, which needs to be stopped. -

BIND10_MSGQ_DISAPPEARED msgq channel disappeared

-While listening on the message bus channel for messages, it suddenly -disappeared. The msgq daemon may have died. This might lead to an -inconsistent state of the system, and BIND 10 will now shut down. -

BIND10_NO_SOCKET couldn't send a socket for token %1 because of error: %2

-An error occurred when the bind10 process was asked to send a socket file -descriptor. The error is mentioned, most common reason is that the request -is invalid and may not come from bind10 process at all. -

BIND10_PROCESS_ENDED process %2 of %1 ended with status %3

-This indicates a process started previously terminated. The process id -and component owning the process are indicated, as well as the exit code. -This doesn't distinguish if the process was supposed to terminate or not. -

BIND10_READING_BOSS_CONFIGURATION reading boss configuration

-The boss process is starting up, and will now process the initial -configuration, as received from the configuration manager. -

BIND10_RECEIVED_COMMAND received command: %1

-The boss module received a command and shall now process it. The command -is printed. -

BIND10_RECEIVED_NEW_CONFIGURATION received new configuration: %1

-The boss module received a configuration update and is going to apply -it now. The new configuration is printed. -

BIND10_RECEIVED_SIGNAL received signal %1

-The boss module received the given signal. -

BIND10_RESURRECTED_PROCESS resurrected %1 (PID %2)

-The given process has been restarted successfully, and is now running -with the given process id. -

BIND10_RESURRECTING_PROCESS resurrecting dead %1 process...

-The given process has ended unexpectedly, and is now restarted. -

BIND10_SELECT_ERROR error in select() call: %1

-There was a fatal error in the call to select(), used to see if a child -process has ended or if there is a message on the message bus. This -should not happen under normal circumstances and is considered fatal, -so BIND 10 will now shut down. The specific error is printed. -

BIND10_SEND_SIGKILL sending SIGKILL to %1 (PID %2)

-The boss module is sending a SIGKILL signal to the given process. -

BIND10_SEND_SIGTERM sending SIGTERM to %1 (PID %2)

-The boss module is sending a SIGTERM signal to the given process. -

BIND10_SETUID setting UID to %1

-The boss switches the user it runs as to the given UID. -

BIND10_SHUTDOWN stopping the server

-The boss process received a command or signal telling it to shut down. -It will send a shutdown command to each process. The processes that do -not shut down will then receive a SIGTERM signal. If that doesn't work, -it shall send SIGKILL signals to the processes still alive. -

BIND10_SHUTDOWN_COMPLETE all processes ended, shutdown complete

-All child processes have been stopped, and the boss process will now -stop itself. -

BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1

-The socket creator reported an error when creating a socket. But the function -which failed is unknown (not one of 'S' for socket or 'B' for bind). -

BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1

-The boss requested a socket from the creator, but the answer is unknown. This -looks like a programmer error. -

BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator

-There should be more data from the socket creator, but it closed the socket. -It probably crashed. -

BIND10_SOCKCREATOR_INIT initializing socket creator parser

-The boss module initializes routines for parsing the socket creator -protocol. -

BIND10_SOCKCREATOR_KILL killing the socket creator

-The socket creator is being terminated the aggressive way, by sending it -sigkill. This should not happen usually. -

BIND10_SOCKCREATOR_TERMINATE terminating socket creator

-The boss module sends a request to terminate to the socket creator. -

BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1

-Either sending or receiving data from the socket creator failed with the given -error. The creator probably crashed or some serious OS-level problem happened, -as the communication happens only on local host. -

BIND10_SOCKET_CREATED successfully created socket %1

-The socket creator successfully created and sent a requested socket, it has -the given file number. -

BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3

-The socket creator failed to create the requested socket. It failed on the -indicated OS API function with given error. -

BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator

-The boss forwards a request for a socket to the socket creator. -

BIND10_STARTED_CC started configuration/command session

-Debug message given when BIND 10 has successfull started the object that -handles configuration and commands. -

BIND10_STARTED_PROCESS started %1

-The given process has successfully been started. -

BIND10_STARTED_PROCESS_PID started %1 (PID %2)

-The given process has successfully been started, and has the given PID. -

BIND10_STARTING starting BIND10: %1

-Informational message on startup that shows the full version. -

BIND10_STARTING_CC starting configuration/command session

-Informational message given when BIND 10 is starting the session object -that handles configuration and commands. -

BIND10_STARTING_PROCESS starting process %1

-The boss module is starting the given process. -

BIND10_STARTING_PROCESS_PORT starting process %1 (to listen on port %2)

-The boss module is starting the given process, which will listen on the -given port number. -

BIND10_STARTING_PROCESS_PORT_ADDRESS starting process %1 (to listen on %2#%3)

-The boss module is starting the given process, which will listen on the -given address and port number (written as <address>#<port>). -

BIND10_STARTUP_COMPLETE BIND 10 started

-All modules have been successfully started, and BIND 10 is now running. -

BIND10_STARTUP_ERROR error during startup: %1

-There was a fatal error when BIND10 was trying to start. The error is -shown, and BIND10 will now shut down. -

BIND10_STARTUP_UNEXPECTED_MESSAGE unrecognised startup message %1

-During the startup process, a number of messages are exchanged between the -Boss process and the processes it starts. This error is output when a -message received by the Boss process is recognised as being of the -correct format but is unexpected. It may be that processes are starting -of sequence. -

BIND10_STARTUP_UNRECOGNISED_MESSAGE unrecognised startup message %1

-During the startup process, a number of messages are exchanged between the -Boss process and the processes it starts. This error is output when a -message received by the Boss process is not recognised. -

BIND10_START_AS_NON_ROOT_AUTH starting b10-auth as a user, not root. This might fail.

-The authoritative server is being started or restarted without root privileges. -If the module needs these privileges, it may have problems starting. -Note that this issue should be resolved by the pending 'socket-creator' -process; once that has been implemented, modules should not need root -privileges anymore. See tickets #800 and #801 for more information. -

BIND10_START_AS_NON_ROOT_RESOLVER starting b10-resolver as a user, not root. This might fail.

-The resolver is being started or restarted without root privileges. -If the module needs these privileges, it may have problems starting. -Note that this issue should be resolved by the pending 'socket-creator' -process; once that has been implemented, modules should not need root -privileges anymore. See tickets #800 and #801 for more information. -

BIND10_STOP_PROCESS asking %1 to shut down

-The boss module is sending a shutdown command to the given module over -the message channel. -

BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited

-An unknown child process has exited. The PID is printed, but no further -action will be taken by the boss process. -

BIND10_WAIT_CFGMGR waiting for configuration manager process to initialize

-The configuration manager process is so critical to operation of BIND 10 -that after starting it, the Boss module will wait for it to initialize -itself before continuing. This debug message is produced during the -wait and may be output zero or more times depending on how long it takes -the configuration manager to start up. The total length of time Boss -will wait for the configuration manager before reporting an error is -set with the command line --wait switch, which has a default value of -ten seconds. -

CACHE_ENTRY_MISSING_RRSET missing RRset to generate message for %1

-The cache tried to generate the complete answer message. It knows the structure -of the message, but some of the RRsets to be put there are not in cache (they -probably expired already). Therefore it pretends the message was not found. -

CACHE_LOCALZONE_FOUND found entry with key %1 in local zone data

-Debug message, noting that the requested data was successfully found in the -local zone data of the cache. -

CACHE_LOCALZONE_UNKNOWN entry with key %1 not found in local zone data

-Debug message. The requested data was not found in the local zone data. -

CACHE_LOCALZONE_UPDATE updating local zone element at key %1

-Debug message issued when there's update to the local zone section of cache. -

CACHE_MESSAGES_DEINIT deinitialized message cache

-Debug message. It is issued when the server deinitializes the message cache. -

CACHE_MESSAGES_EXPIRED found an expired message entry for %1 in the message cache

-Debug message. The requested data was found in the message cache, but it -already expired. Therefore the cache removes the entry and pretends it found -nothing. -

CACHE_MESSAGES_FOUND found a message entry for %1 in the message cache

-Debug message. We found the whole message in the cache, so it can be returned -to user without any other lookups. -

CACHE_MESSAGES_INIT initialized message cache for %1 messages of class %2

-Debug message issued when a new message cache is issued. It lists the class -of messages it can hold and the maximum size of the cache. -

CACHE_MESSAGES_REMOVE removing old instance of %1/%2/%3 first

-Debug message. This may follow CACHE_MESSAGES_UPDATE and indicates that, while -updating, the old instance is being removed prior of inserting a new one. -

CACHE_MESSAGES_UNCACHEABLE not inserting uncacheable message %1/%2/%3

-Debug message, noting that the given message can not be cached. This is because -there's no SOA record in the message. See RFC 2308 section 5 for more -information. -

CACHE_MESSAGES_UNKNOWN no entry for %1 found in the message cache

-Debug message. The message cache didn't find any entry for the given key. -

CACHE_MESSAGES_UPDATE updating message entry %1/%2/%3

-Debug message issued when the message cache is being updated with a new -message. Either the old instance is removed or, if none is found, new one -is created. -

CACHE_RESOLVER_DEEPEST looking up deepest NS for %1/%2

-Debug message. The resolver cache is looking up the deepest known nameserver, -so the resolution doesn't have to start from the root. -

CACHE_RESOLVER_INIT initializing resolver cache for class %1

-Debug message. The resolver cache is being created for this given class. -

CACHE_RESOLVER_INIT_INFO initializing resolver cache for class %1

-Debug message, the resolver cache is being created for this given class. The -difference from CACHE_RESOLVER_INIT is only in different format of passed -information, otherwise it does the same. -

CACHE_RESOLVER_LOCAL_MSG message for %1/%2 found in local zone data

-Debug message. The resolver cache found a complete message for the user query -in the zone data. -

CACHE_RESOLVER_LOCAL_RRSET RRset for %1/%2 found in local zone data

-Debug message. The resolver cache found a requested RRset in the local zone -data. -

CACHE_RESOLVER_LOOKUP_MSG looking up message in resolver cache for %1/%2

-Debug message. The resolver cache is trying to find a message to answer the -user query. -

CACHE_RESOLVER_LOOKUP_RRSET looking up RRset in resolver cache for %1/%2

-Debug message. The resolver cache is trying to find an RRset (which usually -originates as internally from resolver). -

CACHE_RESOLVER_NO_QUESTION answer message for %1/%2 has empty question section

-The cache tried to fill in found data into the response message. But it -discovered the message contains no question section, which is invalid. -This is likely a programmer error, please submit a bug report. -

CACHE_RESOLVER_UNKNOWN_CLASS_MSG no cache for class %1

-Debug message. While trying to lookup a message in the resolver cache, it was -discovered there's no cache for this class at all. Therefore no message is -found. -

CACHE_RESOLVER_UNKNOWN_CLASS_RRSET no cache for class %1

-Debug message. While trying to lookup an RRset in the resolver cache, it was -discovered there's no cache for this class at all. Therefore no data is found. -

CACHE_RESOLVER_UPDATE_MSG updating message for %1/%2/%3

-Debug message. The resolver is updating a message in the cache. -

CACHE_RESOLVER_UPDATE_RRSET updating RRset for %1/%2/%3

-Debug message. The resolver is updating an RRset in the cache. -

CACHE_RESOLVER_UPDATE_UNKNOWN_CLASS_MSG no cache for class %1

-Debug message. While trying to insert a message into the cache, it was -discovered that there's no cache for the class of message. Therefore -the message will not be cached. -

CACHE_RESOLVER_UPDATE_UNKNOWN_CLASS_RRSET no cache for class %1

-Debug message. While trying to insert an RRset into the cache, it was -discovered that there's no cache for the class of the RRset. Therefore -the message will not be cached. -

CACHE_RRSET_EXPIRED found expired RRset %1/%2/%3

-Debug message. The requested data was found in the RRset cache. However, it is -expired, so the cache removed it and is going to pretend nothing was found. -

CACHE_RRSET_INIT initializing RRset cache for %1 RRsets of class %2

-Debug message. The RRset cache to hold at most this many RRsets for the given -class is being created. -

CACHE_RRSET_LOOKUP looking up %1/%2/%3 in RRset cache

-Debug message. The resolver is trying to look up data in the RRset cache. -

CACHE_RRSET_NOT_FOUND no RRset found for %1/%2/%3 in cache

-Debug message which can follow CACHE_RRSET_LOOKUP. This means the data is not -in the cache. -

CACHE_RRSET_REMOVE_OLD removing old RRset for %1/%2/%3 to make space for new one

-Debug message which can follow CACHE_RRSET_UPDATE. During the update, the cache -removed an old instance of the RRset to replace it with the new one. -

CACHE_RRSET_UNTRUSTED not replacing old RRset for %1/%2/%3, it has higher trust level

-Debug message which can follow CACHE_RRSET_UPDATE. The cache already holds the -same RRset, but from more trusted source, so the old one is kept and new one -ignored. -

CACHE_RRSET_UPDATE updating RRset %1/%2/%3 in the cache

-Debug message. The RRset is updating its data with this given RRset. -

CC_ASYNC_READ_FAILED asynchronous read failed

-This marks a low level error, we tried to read data from the message queue -daemon asynchronously, but the ASIO library returned an error. -

CC_CONN_ERROR error connecting to message queue (%1)

-It is impossible to reach the message queue daemon for the reason given. It -is unlikely there'll be reason for whatever program this currently is to -continue running, as the communication with the rest of BIND 10 is vital -for the components. -

CC_DISCONNECT disconnecting from message queue daemon

-The library is disconnecting from the message queue daemon. This debug message -indicates that the program is trying to shut down gracefully. -

CC_ESTABLISH trying to establish connection with message queue daemon at %1

-This debug message indicates that the command channel library is about to -connect to the message queue daemon, which should be listening on the UNIX-domain -socket listed in the output. -

CC_ESTABLISHED successfully connected to message queue daemon

-This debug message indicates that the connection was successfully made, this -should follow CC_ESTABLISH. -

CC_GROUP_RECEIVE trying to receive a message

-Debug message, noting that a message is expected to come over the command -channel. -

CC_GROUP_RECEIVED message arrived ('%1', '%2')

-Debug message, noting that we successfully received a message (its envelope and -payload listed). This follows CC_GROUP_RECEIVE, but might happen some time -later, depending if we waited for it or just polled. -

CC_GROUP_SEND sending message '%1' to group '%2'

-Debug message, we're about to send a message over the command channel. -

CC_INVALID_LENGTHS invalid length parameters (%1, %2)

-This happens when garbage comes over the command channel or some kind of -confusion happens in the program. The data received from the socket make no -sense if we interpret it as lengths of message. The first one is total length -of the message; the second is the length of the header. The header -and its length (2 bytes) is counted in the total length. -

CC_LENGTH_NOT_READY length not ready

-There should be data representing the length of message on the socket, but it -is not there. -

CC_NO_MESSAGE no message ready to be received yet

-The program polled for incoming messages, but there was no message waiting. -This is a debug message which may happen only after CC_GROUP_RECEIVE. -

CC_NO_MSGQ unable to connect to message queue (%1)

-It isn't possible to connect to the message queue daemon, for reason listed. -It is unlikely any program will be able continue without the communication. -

CC_READ_ERROR error reading data from command channel (%1)

-A low level error happened when the library tried to read data from the -command channel socket. The reason is listed. -

CC_READ_EXCEPTION error reading data from command channel (%1)

-We received an exception while trying to read data from the command -channel socket. The reason is listed. -

CC_REPLY replying to message from '%1' with '%2'

-Debug message, noting we're sending a response to the original message -with the given envelope. -

CC_SET_TIMEOUT setting timeout to %1ms

-Debug message. A timeout for which the program is willing to wait for a reply -is being set. -

CC_START_READ starting asynchronous read

-Debug message. From now on, when a message (or command) comes, it'll wake the -program and the library will automatically pass it over to correct place. -

CC_SUBSCRIBE subscribing to communication group %1

-Debug message. The program wants to receive messages addressed to this group. -

CC_TIMEOUT timeout reading data from command channel

-The program waited too long for data from the command channel (usually when it -sent a query to different program and it didn't answer for whatever reason). -

CC_UNSUBSCRIBE unsubscribing from communication group %1

-Debug message. The program no longer wants to receive messages addressed to -this group. -

CC_WRITE_ERROR error writing data to command channel (%1)

-A low level error happened when the library tried to write data to the command -channel socket. -

CC_ZERO_LENGTH invalid message length (0)

-The library received a message length being zero, which makes no sense, since -all messages must contain at least the envelope. -

CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE Updating configuration database from version %1 to %2

-An older version of the configuration database has been found, from which -there was an automatic upgrade path to the current version. These changes -are now applied, and no action from the administrator is necessary. -

CFGMGR_BAD_UPDATE_RESPONSE_FROM_MODULE Unable to parse response from module %1: %2

-The configuration manager sent a configuration update to a module, but -the module responded with an answer that could not be parsed. The answer -message appears to be invalid JSON data, or not decodable to a string. -This is likely to be a problem in the module in question. The update is -assumed to have failed, and will not be stored. -

CFGMGR_CC_SESSION_ERROR Error connecting to command channel: %1

-The configuration manager daemon was unable to connect to the messaging -system. The most likely cause is that msgq is not running. -

CFGMGR_DATA_READ_ERROR error reading configuration database from disk: %1

-There was a problem reading the persistent configuration data as stored -on disk. The file may be corrupted, or it is of a version from where -there is no automatic upgrade path. The file needs to be repaired or -removed. The configuration manager daemon will now shut down. -

CFGMGR_IOERROR_WHILE_WRITING_CONFIGURATION Unable to write configuration file; configuration not stored: %1

-There was an IO error from the system while the configuration manager -was trying to write the configuration database to disk. The specific -error is given. The most likely cause is that the directory where -the file is stored does not exist, or is not writable. The updated -configuration is not stored. -

CFGMGR_OSERROR_WHILE_WRITING_CONFIGURATION Unable to write configuration file; configuration not stored: %1

-There was an OS error from the system while the configuration manager -was trying to write the configuration database to disk. The specific -error is given. The most likely cause is that the system does not have -write access to the configuration database file. The updated -configuration is not stored. -

CFGMGR_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the cfgmgr daemon. The -daemon will now shut down. -

CMDCTL_BAD_CONFIG_DATA error in config data: %1

-There was an error reading the updated configuration data. The specific -error is printed. -

CMDCTL_BAD_PASSWORD bad password for user: %1

-A login attempt was made to b10-cmdctl, but the password was wrong. -Users can be managed with the tool b10-cmdctl-usermgr. -

CMDCTL_CC_SESSION_ERROR error reading from cc channel: %1

-There was a problem reading from the command and control channel. The -most likely cause is that the message bus daemon is not running. -

CMDCTL_CC_SESSION_TIMEOUT timeout on cc channel

-A timeout occurred when waiting for essential data from the cc session. -This usually occurs when b10-cfgmgr is not running or not responding. -Since we are waiting for essential information, this is a fatal error, -and the cmdctl daemon will now shut down. -

CMDCTL_COMMAND_ERROR error in command %1 to module %2: %3

-An error was encountered sending the given command to the given module. -Either there was a communication problem with the module, or the module -was not able to process the command, and sent back an error. The -specific error is printed in the message. -

CMDCTL_COMMAND_SENT command '%1' to module '%2' was sent

-This debug message indicates that the given command has been sent to -the given module. -

CMDCTL_NO_SUCH_USER username not found in user database: %1

-A login attempt was made to b10-cmdctl, but the username was not known. -Users can be added with the tool b10-cmdctl-usermgr. -

CMDCTL_NO_USER_ENTRIES_READ failed to read user information, all users will be denied

-The b10-cmdctl daemon was unable to find any user data in the user -database file. Either it was unable to read the file (in which case -this message follows a message CMDCTL_USER_DATABASE_READ_ERROR -containing a specific error), or the file was empty. Users can be added -with the tool b10-cmdctl-usermgr. -

CMDCTL_SEND_COMMAND sending command %1 to module %2

-This debug message indicates that the given command is being sent to -the given module. -

CMDCTL_SSL_SETUP_FAILURE_USER_DENIED failed to create an SSL connection (user denied): %1

-The user was denied because the SSL connection could not successfully -be set up. The specific error is given in the log message. Possible -causes may be that the ssl request itself was bad, or the local key or -certificate file could not be read. -

CMDCTL_STARTED cmdctl is listening for connections on %1:%2

-The cmdctl daemon has started and is now listening for connections. -

CMDCTL_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the cmdctl daemon. The -daemon will now shut down. -

CMDCTL_UNCAUGHT_EXCEPTION uncaught exception: %1

-The b10-cmdctl daemon encountered an uncaught exception and -will now shut down. This is indicative of a programming error and -should not happen under normal circumstances. The exception message -is printed. -

CMDCTL_USER_DATABASE_READ_ERROR failed to read user database file %1: %2

-The b10-cmdctl daemon was unable to read the user database file. The -file may be unreadable for the daemon, or it may be corrupted. In the -latter case, it can be recreated with b10-cmdctl-usermgr. The specific -error is printed in the log message. -

CONFIG_CCSESSION_MSG error in CC session message: %1

-There was a problem with an incoming message on the command and control -channel. The message does not appear to be a valid command, and is -missing a required element or contains an unknown data format. This -most likely means that another BIND10 module is sending a bad message. -The message itself is ignored by this module. -

CONFIG_CCSESSION_MSG_INTERNAL error handling CC session message: %1

-There was an internal problem handling an incoming message on the command -and control channel. An unexpected exception was thrown, details of -which are appended to the message. The module will continue to run, -but will not send back an answer. -

-The most likely cause of this error is a programming error. Please raise -a bug report. -

CONFIG_GET_FAIL error getting configuration from cfgmgr: %1

-The configuration manager returned an error when this module requested -the configuration. The full error message answer from the configuration -manager is appended to the log error. The most likely cause is that -the module is of a different (command specification) version than the -running configuration manager. -

CONFIG_GET_FAILED error getting configuration from cfgmgr: %1

-The configuration manager returned an error response when the module -requested its configuration. The full error message answer from the -configuration manager is appended to the log error. -

CONFIG_JSON_PARSE JSON parse error in %1: %2

-There was an error parsing the JSON file. The given file does not appear -to be in valid JSON format. Please verify that the filename is correct -and that the contents are valid JSON. -

CONFIG_LOG_CONFIG_ERRORS error(s) in logging configuration: %1

-There was a logging configuration update, but the internal validator -for logging configuration found that it contained errors. The errors -are shown, and the update is ignored. -

CONFIG_LOG_EXPLICIT will use logging configuration for explicitly-named logger %1

-This is a debug message. When processing the "loggers" part of the -configuration file, the configuration library found an entry for the named -logger that matches the logger specification for the program. The logging -configuration for the program will be updated with the information. -

CONFIG_LOG_IGNORE_EXPLICIT ignoring logging configuration for explicitly-named logger %1

-This is a debug message. When processing the "loggers" part of the -configuration file, the configuration library found an entry for the -named logger. As this does not match the logger specification for the -program, it has been ignored. -

CONFIG_LOG_IGNORE_WILD ignoring logging configuration for wildcard logger %1

-This is a debug message. When processing the "loggers" part of the -configuration file, the configuration library found the named wildcard -entry (one containing the "*" character) that matched a logger already -matched by an explicitly named entry. The configuration is ignored. -

CONFIG_LOG_WILD_MATCH will use logging configuration for wildcard logger %1

-This is a debug message. When processing the "loggers" part of -the configuration file, the configuration library found the named -wildcard entry (one containing the "*" character) that matches a logger -specification in the program. The logging configuration for the program -will be updated with the information. -

CONFIG_MOD_SPEC_FORMAT module specification error in %1: %2

-The given file does not appear to be a valid specification file: details -are included in the message. Please verify that the filename is correct -and that its contents are a valid BIND10 module specification. -

CONFIG_MOD_SPEC_REJECT module specification rejected by cfgmgr: %1

-The specification file for this module was rejected by the configuration -manager. The full error message answer from the configuration manager is -appended to the log error. The most likely cause is that the module is of -a different (specification file) version than the running configuration -manager. -

CONFIG_OPEN_FAIL error opening %1: %2

-There was an error opening the given file. The reason for the failure -is included in the message. -

DATASRC_CACHE_CREATE creating the hotspot cache

-This is a debug message issued during startup when the hotspot cache -is created. -

DATASRC_CACHE_DESTROY destroying the hotspot cache

-Debug information. The hotspot cache is being destroyed. -

DATASRC_CACHE_DISABLE disabling the hotspot cache

-A debug message issued when the hotspot cache is disabled. -

DATASRC_CACHE_ENABLE enabling the hotspot cache

-A debug message issued when the hotspot cache is enabled. -

DATASRC_CACHE_EXPIRED item '%1' in the hotspot cache has expired

-A debug message issued when a hotspot cache lookup located the item but it -had expired. The item was removed and the program proceeded as if the item -had not been found. -

DATASRC_CACHE_FOUND the item '%1' was found

-Debug information. An item was successfully located in the hotspot cache. -

DATASRC_CACHE_FULL hotspot cache is full, dropping oldest

-Debug information. After inserting an item into the hotspot cache, the -maximum number of items was exceeded, so the least recently used item will -be dropped. This should be directly followed by CACHE_REMOVE. -

DATASRC_CACHE_INSERT inserting item '%1' into the hotspot cache

-A debug message indicating that a new item is being inserted into the hotspot -cache. -

DATASRC_CACHE_NOT_FOUND the item '%1' was not found in the hotspot cache

-A debug message issued when hotspot cache was searched for the specified -item but it was not found. -

DATASRC_CACHE_OLD_FOUND older instance of hotspot cache item '%1' found, replacing

-Debug information. While inserting an item into the hotspot cache, an older -instance of an item with the same name was found; the old instance will be -removed. This will be directly followed by CACHE_REMOVE. -

DATASRC_CACHE_REMOVE removing '%1' from the hotspot cache

-Debug information. An item is being removed from the hotspot cache. -

DATASRC_CACHE_SLOTS setting the hotspot cache size to '%1', dropping '%2' items

-The maximum allowed number of items of the hotspot cache is set to the given -number. If there are too many, some of them will be dropped. The size of 0 -means no limit. -

DATASRC_DATABASE_COVER_NSEC_UNSUPPORTED %1 doesn't support DNSSEC when asked for NSEC data covering %2

-The datasource tried to provide an NSEC proof that the named domain does not -exist, but the database backend doesn't support DNSSEC. No proof is included -in the answer as a result. -

DATASRC_DATABASE_FIND_RECORDS looking in datasource %1 for record %2/%3/%4

-Debug information. The database data source is looking up records with the given -name and type in the database. -

DATASRC_DATABASE_FIND_TTL_MISMATCH TTL values differ in %1 for elements of %2/%3/%4, setting to %5

-The datasource backend provided resource records for the given RRset with -different TTL values. This isn't allowed on the wire and is considered -an error, so we set it to the lowest value we found (but we don't modify the -database). The data in database should be checked and fixed. -

DATASRC_DATABASE_FOUND_ANY search in datasource %1 resulted in returning all records of %2

-The data returned by the database backend contained data for the given domain -name, so all the RRsets of the domain are returned. -

DATASRC_DATABASE_FOUND_CNAME search in datasource %1 for %2/%3/%4 found CNAME, resulting in %5

-When searching the domain for a name a CNAME was found at that name. -Even though it was not the RR type being sought, it is returned. (The -caller may want to continue the lookup by replacing the query name with -the canonical name and restarting the query with the original RR type.) -

DATASRC_DATABASE_FOUND_DELEGATION Found delegation at %2 in %1

-When searching for a domain, the program met a delegation to a different zone -at the given domain name. It will return that one instead. -

DATASRC_DATABASE_FOUND_DELEGATION_EXACT search in datasource %1 for %2/%3/%4 found delegation at %5

-The program found the domain requested, but it is a delegation point to a -different zone, therefore it is not authoritative for this domain name. -It will return the NS record instead. -

DATASRC_DATABASE_FOUND_DNAME Found DNAME at %2 in %1

-When searching for a domain, the program met a DNAME redirection to a different -place in the domain space at the given domain name. It will return that one -instead. -

DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL empty non-terminal %2 in %1

-The domain name does not have any RRs associated with it, so it doesn't -exist in the database. However, it has a subdomain, so it does exist -in the DNS address space. This type of domain is known an an "empty -non-terminal" and so we return NXRRSET instead of NXDOMAIN. -

DATASRC_DATABASE_FOUND_NXDOMAIN search in datasource %1 resulted in NXDOMAIN for %2/%3/%4

-The data returned by the database backend did not contain any data for the given -domain name, class and type. -

DATASRC_DATABASE_FOUND_NXRRSET search in datasource %1 for %2/%3/%4 resulted in NXRRSET

-The data returned by the database backend contained data for the given domain -name and class, but not for the given type. -

DATASRC_DATABASE_FOUND_NXRRSET_NSEC search in datasource %1 for %2/%3/%4 resulted in RRset %5

-A search in the database for RRs for the specified name, type and class has -located RRs that match the name and class but not the type. DNSSEC information -has been requested and returned. -

DATASRC_DATABASE_FOUND_RRSET search in datasource %1 resulted in RRset %5

-The data returned by the database backend contained data for the given domain -name, and it either matches the type or has a relevant type. The RRset that is -returned is printed. -

DATASRC_DATABASE_ITERATE iterating zone %1

-The program is reading the whole zone, eg. not searching for data, but going -through each of the RRsets there. -

DATASRC_DATABASE_ITERATE_END iterating zone finished

-While iterating through the zone, the program reached end of the data. -

DATASRC_DATABASE_ITERATE_NEXT next RRset in zone is %1/%2

-While iterating through the zone, the program extracted next RRset from it. -The name and RRtype of the RRset is indicated in the message. -

DATASRC_DATABASE_ITERATE_TTL_MISMATCH TTL values differ for RRs of %1/%2/%3, setting to %4

-While iterating through the zone, the time to live for RRs of the given RRset -were found to be different. This isn't allowed on the wire and is considered -an error, so we set it to the lowest value we found (but we don't modify the -database). The data in database should be checked and fixed. -

DATASRC_DATABASE_JOURNALREADER_END %1/%2 on %3 from %4 to %5

-This is a debug message indicating that the program (successfully) -reaches the end of sequences of a zone's differences. The zone's name -and class, database name, and the start and end serials are shown in -the message. -

DATASRC_DATABASE_JOURNALREADER_NEXT %1/%2 in %3/%4 on %5

-This is a debug message indicating that the program retrieves one -difference in difference sequences of a zone and successfully converts -it to an RRset. The zone's name and class, database name, and the -name and RR type of the retrieved diff are shown in the message. -

DATASRC_DATABASE_JOURNALREADER_START %1/%2 on %3 from %4 to %5

-This is a debug message indicating that the program starts reading -a zone's difference sequences from a database-based data source. The -zone's name and class, database name, and the start and end serials -are shown in the message. -

DATASRC_DATABASE_JOURNALREADR_BADDATA failed to convert a diff to RRset in %1/%2 on %3 between %4 and %5: %6

-This is an error message indicating that a zone's diff is broken and -the data source library failed to convert it to a valid RRset. The -most likely cause of this is that someone has manually modified the -zone's diff in the database and inserted invalid data as a result. -The zone's name and class, database name, and the start and end -serials, and an additional detail of the error are shown in the -message. The administrator should examine the diff in the database -to find any invalid data and fix it. -

DATASRC_DATABASE_NO_MATCH not match for %2/%3/%4 in %1

-No match (not even a wildcard) was found in the named data source for the given -name/type/class in the data source. -

DATASRC_DATABASE_UPDATER_COMMIT updates committed for '%1/%2' on %3

-Debug information. A set of updates to a zone has been successfully -committed to the corresponding database backend. The zone name, -its class and the database name are printed. -

DATASRC_DATABASE_UPDATER_COMMIT (1) updates committed for '%1/%2' on %3

-Debug information. A set of updates to a zone has been successfully -committed to the corresponding database backend. The zone name, -its class and the database name are printed. -

DATASRC_DATABASE_UPDATER_CREATED zone updater created for '%1/%2' on %3

-Debug information. A zone updater object is created to make updates to -the shown zone on the shown backend database. -

DATASRC_DATABASE_UPDATER_CREATED (1) zone updater created for '%1/%2' on %3

-Debug information. A zone updater object is created to make updates to -the shown zone on the shown backend database. -

DATASRC_DATABASE_UPDATER_DESTROYED zone updater destroyed for '%1/%2' on %3

-Debug information. A zone updater object is destroyed, either successfully -or after failure of, making updates to the shown zone on the shown backend -database. -

DATASRC_DATABASE_UPDATER_DESTROYED (1) zone updater destroyed for '%1/%2' on %3

-Debug information. A zone updater object is destroyed, either successfully -or after failure of, making updates to the shown zone on the shown backend -database. -

DATASRC_DATABASE_UPDATER_ROLLBACK zone updates roll-backed for '%1/%2' on %3

-A zone updater is being destroyed without committing the changes. -This would typically mean the update attempt was aborted due to some -error, but may also be a bug of the application that forgets committing -the changes. The intermediate changes made through the updater won't -be applied to the underlying database. The zone name, its class, and -the underlying database name are shown in the log message. -

DATASRC_DATABASE_UPDATER_ROLLBACK (1) zone updates roll-backed for '%1/%2' on %3

-A zone updater is being destroyed without committing the changes. -This would typically mean the update attempt was aborted due to some -error, but may also be a bug of the application that forgets committing -the changes. The intermediate changes made through the updater won't -be applied to the underlying database. The zone name, its class, and -the underlying database name are shown in the log message. -

DATASRC_DATABASE_UPDATER_ROLLBACKFAIL failed to roll back zone updates for '%1/%2' on %3: %4

-A zone updater is being destroyed without committing the changes to -the database, and attempts to rollback incomplete updates, but it -unexpectedly fails. The higher level implementation does not expect -it to fail, so this means either a serious operational error in the -underlying data source (such as a system failure of a database) or -software bug in the underlying data source implementation. In either -case if this message is logged the administrator should carefully -examine the underlying data source to see what exactly happens and -whether the data is still valid. The zone name, its class, and the -underlying database name as well as the error message thrown from the -database module are shown in the log message. -

DATASRC_DATABASE_UPDATER_ROLLBACKFAIL (1) failed to roll back zone updates for '%1/%2' on %3: %4

-A zone updater is being destroyed without committing the changes to -the database, and attempts to rollback incomplete updates, but it -unexpectedly fails. The higher level implementation does not expect -it to fail, so this means either a serious operational error in the -underlying data source (such as a system failure of a database) or -software bug in the underlying data source implementation. In either -case if this message is logged the administrator should carefully -examine the underlying data source to see what exactly happens and -whether the data is still valid. The zone name, its class, and the -underlying database name as well as the error message thrown from the -database module are shown in the log message. -

DATASRC_DATABASE_WILDCARD_ANY search in datasource %1 resulted in wildcard match type ANY on %2

-The database doesn't contain directly matching name. When searching -for a wildcard match, a wildcard record matching the name of the query -containing some RRsets was found. All the RRsets of the node are returned. -

DATASRC_DATABASE_WILDCARD_CANCEL_NS canceled wildcard match on %3 because %2 contains NS (data source %1)

-The database was queried to provide glue data and it didn't find direct match. -It could create it from given wildcard, but matching wildcards is forbidden -under a zone cut, which was found. Therefore the delegation will be returned -instead. -

DATASRC_DATABASE_WILDCARD_CANCEL_SUB wildcard %2 can't be used to construct %3 because %4 exists in %1

-The answer could be constructed using the wildcard, but the given subdomain -exists, therefore this name is something like empty non-terminal (actually, -from the protocol point of view, it is empty non-terminal, but the code -discovers it differently). -

DATASRC_DATABASE_WILDCARD_CNAME search in datasource %1 for %2/%3/%4 found wildcard CNAME at %5, resulting in %6

-The database doesn't contain directly matching name. When searching -for a wildcard match, a CNAME RR was found at a wildcard record -matching the name. This is returned as the result of the search. -

DATASRC_DATABASE_WILDCARD_EMPTY found subdomains of %2 which is a wildcard match for %3 in %1

-The given wildcard matches the name being sough but it as an empty -nonterminal (e.g. there's nothing at *.example.com but something like -subdomain.*.example.org, do exist: so *.example.org exists in the -namespace but has no RRs assopciated with it). This will produce NXRRSET. -

DATASRC_DATABASE_WILDCARD_MATCH search in datasource %1 resulted in wildcard match at %5 with RRset %6

-The database doesn't contain directly matching name. When searching -for a wildcard match, a wildcard record matching the name and type of -the query was found. The data at this point is returned. -

DATASRC_DATABASE_WILDCARD_NS search in datasource %1 for %2/%3/%4 found wildcard delegation at %5, resulting in %6

-The database doesn't contain directly matching name. When searching -for a wildcard match, an NS RR was found at a wildcard record matching -the name. This is returned as the result of the search. -

DATASRC_DATABASE_WILDCARD_NXRRSET search in datasource %1 for %2/%3/%4 resulted in wildcard NXRRSET at %5

-The database doesn't contain directly matching name. When searching -for a wildcard match, a matching wildcard entry was found but it did -not contain RRs the requested type. AN NXRRSET indication is returned. -

DATASRC_DO_QUERY handling query for '%1/%2'

-A debug message indicating that a query for the given name and RR type is being -processed. -

DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'

-Debug information. An RRset is being added to the in-memory data source. -

DATASRC_MEM_ADD_WILDCARD adding wildcards for '%1'

-This is a debug message issued during the processing of a wildcard -name. The internal domain name tree is scanned and some nodes are -specially marked to allow the wildcard lookup to succeed. -

DATASRC_MEM_ADD_ZONE adding zone '%1/%2'

-Debug information. A zone is being added into the in-memory data source. -

DATASRC_MEM_ANY_SUCCESS ANY query for '%1' successful

-Debug information. The domain was found and an ANY type query is being answered -by providing everything found inside the domain. -

DATASRC_MEM_CNAME CNAME at the domain '%1'

-Debug information. The requested domain is an alias to a different domain, -returning the CNAME instead. -

DATASRC_MEM_CNAME_COEXIST can't add data to CNAME in domain '%1'

-This is the same problem as in MEM_CNAME_TO_NONEMPTY, but it happened the -other way around -- adding some other data to CNAME. -

DATASRC_MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1'

-Someone or something tried to add a CNAME into a domain that already contains -some other data. But the protocol forbids coexistence of CNAME with anything -(RFC 1034, section 3.6.2). This indicates a problem with provided data. -

DATASRC_MEM_CREATE creating zone '%1' in '%2' class

-Debug information. A representation of a zone for the in-memory data source is -being created. -

DATASRC_MEM_DELEG_FOUND delegation found at '%1'

-Debug information. A delegation point was found above the requested record. -

DATASRC_MEM_DESTROY destroying zone '%1' in '%2' class

-Debug information. A zone from in-memory data source is being destroyed. -

DATASRC_MEM_DNAME_ENCOUNTERED encountered a DNAME

-Debug information. While searching for the requested domain, a DNAME was -encountered on the way. This may lead to redirection to a different domain and -stop the search. -

DATASRC_MEM_DNAME_FOUND DNAME found at '%1'

-Debug information. A DNAME was found instead of the requested information. -

DATASRC_MEM_DNAME_NS DNAME and NS can't coexist in non-apex domain '%1'

-A request was made for DNAME and NS records to be put into the same -domain which is not the apex (the top of the zone). This is forbidden -by RFC 2672 (section 3) and indicates a problem with provided data. -

DATASRC_MEM_DOMAIN_EMPTY requested domain '%1' is empty

-Debug information. The requested domain exists in the tree of domains, but -it is empty. Therefore it doesn't contain the requested resource type. -

DATASRC_MEM_DUP_RRSET duplicate RRset '%1/%2'

-An RRset is being inserted into in-memory data source for a second time. The -original version must be removed first. Note that loading master files where an -RRset is split into multiple locations is not supported yet. -

DATASRC_MEM_EXACT_DELEGATION delegation at the exact domain '%1'

-Debug information. There's a NS record at the requested domain. This means -this zone is not authoritative for the requested domain, but a delegation -should be followed. The requested domain is an apex of some zone. -

DATASRC_MEM_FIND find '%1/%2'

-Debug information. A search for the requested RRset is being started. -

DATASRC_MEM_FIND_ZONE looking for zone '%1'

-Debug information. A zone object for this zone is being searched for in the -in-memory data source. -

DATASRC_MEM_LOAD loading zone '%1' from file '%2'

-Debug information. The content of master file is being loaded into the memory. -

DATASRC_MEM_NOT_FOUND requested domain '%1' not found

-Debug information. The requested domain does not exist. -

DATASRC_MEM_NS_ENCOUNTERED encountered a NS

-Debug information. While searching for the requested domain, a NS was -encountered on the way (a delegation). This may lead to stop of the search. -

DATASRC_MEM_NXRRSET no such type '%1' at '%2'

-Debug information. The domain exists, but it doesn't hold any record of the -requested type. -

DATASRC_MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2'

-It was attempted to add the domain into a zone that shouldn't have it -(eg. the domain is not subdomain of the zone origin). This indicates a -problem with provided data. -

DATASRC_MEM_RENAME renaming RRset from '%1' to '%2'

-Debug information. A RRset is being generated from a different RRset (most -probably a wildcard). So it must be renamed to whatever the user asked for. In -fact, it's impossible to rename RRsets with our libraries, so a new one is -created and all resource records are copied over. -

DATASRC_MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2'

-Some resource types are singletons -- only one is allowed in a domain -(for example CNAME or SOA). This indicates a problem with provided data. -

DATASRC_MEM_SUCCESS query for '%1/%2' successful

-Debug information. The requested record was found. -

DATASRC_MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty

-Debug information. The search stopped at a superdomain of the requested -domain. The domain is an empty nonterminal, therefore it is treated as NXRRSET -case (eg. the domain exists, but it doesn't have the requested record type). -

DATASRC_MEM_SWAP swapping contents of two zone representations ('%1' and '%2')

-Debug information. The contents of two in-memory zones are being exchanged. -This is usual practice to do some manipulation in exception-safe manner -- the -new data are prepared in a different zone object and when it works, they are -swapped. The old one contains the new data and the other one can be safely -destroyed. -

DATASRC_MEM_WILDCARD_CANCEL wildcard match canceled for '%1'

-Debug information. A domain above wildcard was reached, but there's something -below the requested domain. Therefore the wildcard doesn't apply here. This -behaviour is specified by RFC 1034, section 4.3.3 -

DATASRC_MEM_WILDCARD_DNAME DNAME record in wildcard domain '%1'

-The software refuses to load DNAME records into a wildcard domain. It isn't -explicitly forbidden, but the protocol is ambiguous about how this should -behave and BIND 9 refuses that as well. Please describe your intention using -different tools. -

DATASRC_MEM_WILDCARD_NS NS record in wildcard domain '%1'

-The software refuses to load NS records into a wildcard domain. It isn't -explicitly forbidden, but the protocol is ambiguous about how this should -behave and BIND 9 refuses that as well. Please describe your intention using -different tools. -

DATASRC_META_ADD adding a data source into meta data source

-This is a debug message issued during startup or reconfiguration. -Another data source is being added into the meta data source. -

DATASRC_META_ADD_CLASS_MISMATCH mismatch between classes '%1' and '%2'

-It was attempted to add a data source into a meta data source, but their -classes do not match. -

DATASRC_META_REMOVE removing data source from meta data source

-Debug information. A data source is being removed from meta data source. -

DATASRC_QUERY_ADD_NSEC adding NSEC record for '%1'

-Debug information. A NSEC record covering this zone is being added. -

DATASRC_QUERY_ADD_NSEC3 adding NSEC3 record of zone '%1'

-Debug information. A NSEC3 record for the given zone is being added to the -response message. -

DATASRC_QUERY_ADD_RRSET adding RRset '%1/%2' to message

-Debug information. An RRset is being added to the response message. -

DATASRC_QUERY_ADD_SOA adding SOA of '%1'

-Debug information. A SOA record of the given zone is being added to the -authority section of the response message. -

DATASRC_QUERY_AUTH_FAIL the underlying data source failed with %1

-The underlying data source failed to answer the authoritative query. 1 means -some error, 2 is not implemented. The data source should have logged the -specific error already. -

DATASRC_QUERY_BAD_REFERRAL bad referral to '%1'

-The domain lives in another zone. But it is not possible to generate referral -information for it. -

DATASRC_QUERY_CACHED data for %1/%2 found in hotspot cache

-Debug information. The requested data were found in the hotspot cache, so -no query is sent to the real data source. -

DATASRC_QUERY_CHECK_CACHE checking hotspot cache for '%1/%2'

-Debug information. While processing a query, lookup to the hotspot cache -is being made. -

DATASRC_QUERY_COPY_AUTH copying authoritative section into message

-Debug information. The whole referral information is being copied into the -response message. -

DATASRC_QUERY_DELEGATION looking for delegation on the path to '%1'

-Debug information. The software is trying to identify delegation points on the -way down to the given domain. -

DATASRC_QUERY_EMPTY_CNAME CNAME at '%1' is empty

-A CNAME chain was being followed and an entry was found that pointed -to a domain name that had no RRsets associated with it. As a result, -the query cannot be answered. This indicates a problem with supplied data. -

DATASRC_QUERY_EMPTY_DNAME the DNAME on '%1' is empty

-During an attempt to synthesize CNAME from this DNAME it was discovered the -DNAME is empty (it has no records). This indicates problem with supplied data. -

DATASRC_QUERY_FAIL query failed

-Some subtask of query processing failed. The reason should have been reported -already and a SERVFAIL will be returned to the querying system. -

DATASRC_QUERY_FOLLOW_CNAME following CNAME at '%1'

-Debug information. The domain is a CNAME (or a DNAME and a CNAME for it -has already been created) and the search is following this chain. -

DATASRC_QUERY_GET_MX_ADDITIONAL addition of A/AAAA for '%1' requested by MX '%2'

-Debug information. While processing a query, a MX record was met. It -references the mentioned address, so A/AAAA records for it are looked up -and put it into the additional section. -

DATASRC_QUERY_GET_NS_ADDITIONAL addition of A/AAAA for '%1' requested by NS '%2'

-Debug information. While processing a query, a NS record was met. It -references the mentioned address, so A/AAAA records for it are looked up -and put it into the additional section. -

DATASRC_QUERY_GLUE_FAIL the underlying data source failed with %1

-The underlying data source failed to answer the glue query. 1 means some error, -2 is not implemented. The data source should have logged the specific error -already. -

DATASRC_QUERY_INVALID_OP invalid query operation requested

-This indicates a programmer error. The DO_QUERY was called with unknown -operation code. -

DATASRC_QUERY_IS_AUTH auth query (%1/%2)

-Debug information. The last DO_QUERY is an auth query. -

DATASRC_QUERY_IS_GLUE glue query (%1/%2)

-Debug information. The last DO_QUERY is a query for glue addresses. -

DATASRC_QUERY_IS_NOGLUE query for non-glue addresses (%1/%2)

-Debug information. The last DO_QUERY is a query for addresses that are not -glue. -

DATASRC_QUERY_IS_REF query for referral (%1/%2)

-Debug information. The last DO_QUERY is a query for referral information. -

DATASRC_QUERY_IS_SIMPLE simple query (%1/%2)

-Debug information. The last DO_QUERY is a simple query. -

DATASRC_QUERY_MISPLACED_TASK task of this type should not be here

-This indicates a programming error. A task was found in the internal task -queue, but this kind of task wasn't designed to be inside the queue (it should -be handled right away, not queued). -

DATASRC_QUERY_MISSING_NS missing NS records for '%1'

-NS records should have been put into the authority section. However, this zone -has none. This indicates problem with provided data. -

DATASRC_QUERY_MISSING_SOA the zone '%1' has no SOA

-The answer should have been a negative one (eg. of nonexistence of something). -To do so, a SOA record should be put into the authority section, but the zone -does not have one. This indicates problem with provided data. -

DATASRC_QUERY_NOGLUE_FAIL the underlying data source failed with %1

-The underlying data source failed to answer the no-glue query. 1 means some -error, 2 is not implemented. The data source should have logged the specific -error already. -

DATASRC_QUERY_NO_CACHE_ANY_AUTH ignoring hotspot cache for ANY query (%1/%2 in %3 class)

-Debug information. The hotspot cache is ignored for authoritative ANY queries -for consistency reasons. -

DATASRC_QUERY_NO_CACHE_ANY_SIMPLE ignoring hotspot cache for ANY query (%1/%2 in %3 class)

-Debug information. The hotspot cache is ignored for ANY queries for consistency -reasons. -

DATASRC_QUERY_NO_DS_NSEC there's no DS record in the '%1' zone

-An attempt to add a NSEC record into the message failed, because the zone does -not have any DS record. This indicates problem with the provided data. -

DATASRC_QUERY_NO_DS_NSEC3 there's no DS record in the '%1' zone

-An attempt to add a NSEC3 record into the message failed, because the zone does -not have any DS record. This indicates problem with the provided data. -

DATASRC_QUERY_NO_ZONE no zone containing '%1' in class '%2'

-Lookup of domain failed because the data have no zone that contain the -domain. Maybe someone sent a query to the wrong server for some reason. -

DATASRC_QUERY_PROCESS processing query '%1/%2' in the '%3' class

-Debug information. A sure query is being processed now. -

DATASRC_QUERY_PROVE_NX_FAIL unable to prove nonexistence of '%1'

-The user wants DNSSEC and we discovered the entity doesn't exist (either -domain or the record). But there was an error getting NSEC/NSEC3 record -to prove the nonexistence. -

DATASRC_QUERY_REF_FAIL the underlying data source failed with %1

-The underlying data source failed to answer the query for referral information. -1 means some error, 2 is not implemented. The data source should have logged -the specific error already. -

DATASRC_QUERY_RRSIG unable to answer RRSIG query

-The server is unable to answer a direct query for RRSIG type, but was asked -to do so. -

DATASRC_QUERY_SIMPLE_FAIL the underlying data source failed with %1

-The underlying data source failed to answer the simple query. 1 means some -error, 2 is not implemented. The data source should have logged the specific -error already. -

DATASRC_QUERY_SYNTH_CNAME synthesizing CNAME from DNAME on '%1'

-This is a debug message. While answering a query, a DNAME was encountered. The -DNAME itself will be returned, along with a synthesized CNAME for clients that -do not understand the DNAME RR. -

DATASRC_QUERY_TASK_FAIL task failed with %1

-The query subtask failed. The reason should have been reported by the subtask -already. The code is 1 for error, 2 for not implemented. -

DATASRC_QUERY_TOO_MANY_CNAMES CNAME chain limit exceeded at '%1'

-A CNAME led to another CNAME and it led to another, and so on. After 16 -CNAMEs, the software gave up. Long CNAME chains are discouraged, and this -might possibly be a loop as well. Note that some of the CNAMEs might have -been synthesized from DNAMEs. This indicates problem with supplied data. -

DATASRC_QUERY_UNKNOWN_RESULT unknown result of subtask

-This indicates a programmer error. The answer of subtask doesn't look like -anything known. -

DATASRC_QUERY_WILDCARD looking for a wildcard covering '%1'

-Debug information. A direct match wasn't found, so a wildcard covering the -domain is being looked for now. -

DATASRC_QUERY_WILDCARD_FAIL error processing wildcard for '%1'

-During an attempt to cover the domain by a wildcard an error happened. The -exact kind was hopefully already reported. -

DATASRC_QUERY_WILDCARD_PROVE_NX_FAIL unable to prove nonexistence of '%1' (%2)

-While processing a wildcard, it wasn't possible to prove nonexistence of the -given domain or record. The code is 1 for error and 2 for not implemented. -

DATASRC_QUERY_WILDCARD_REFERRAL unable to find referral info for '%1' (%2)

-While processing a wildcard, a referral was met. But it wasn't possible to get -enough information for it. The code is 1 for error, 2 for not implemented. -

DATASRC_SQLITE_CLOSE closing SQLite database

-Debug information. The SQLite data source is closing the database file. -

DATASRC_SQLITE_CONNCLOSE Closing sqlite database

-The database file is no longer needed and is being closed. -

DATASRC_SQLITE_CONNOPEN Opening sqlite database file '%1'

-The database file is being opened so it can start providing data. -

DATASRC_SQLITE_CREATE SQLite data source created

-Debug information. An instance of SQLite data source is being created. -

DATASRC_SQLITE_DESTROY SQLite data source destroyed

-Debug information. An instance of SQLite data source is being destroyed. -

DATASRC_SQLITE_DROPCONN SQLite3Database is being deinitialized

-The object around a database connection is being destroyed. -

DATASRC_SQLITE_ENCLOSURE looking for zone containing '%1'

-Debug information. The SQLite data source is trying to identify which zone -should hold this domain. -

DATASRC_SQLITE_ENCLOSURE_NOT_FOUND no zone contains '%1'

-Debug information. The last SQLITE_ENCLOSURE query was unsuccessful; there's -no such zone in our data. -

DATASRC_SQLITE_FIND looking for RRset '%1/%2'

-Debug information. The SQLite data source is looking up a resource record -set. -

DATASRC_SQLITE_FINDADDRS looking for A/AAAA addresses for '%1'

-Debug information. The data source is looking up the addresses for given -domain name. -

DATASRC_SQLITE_FINDADDRS_BAD_CLASS class mismatch looking for addresses ('%1' and '%2')

-The SQLite data source was looking up A/AAAA addresses, but the data source -contains different class than the query was for. -

DATASRC_SQLITE_FINDEXACT looking for exact RRset '%1/%2'

-Debug information. The SQLite data source is looking up an exact resource -record. -

DATASRC_SQLITE_FINDEXACT_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')

-The SQLite data source was looking up an exact RRset, but the data source -contains different class than the query was for. -

DATASRC_SQLITE_FINDREC looking for record '%1/%2'

-Debug information. The SQLite data source is looking up records of given name -and type in the database. -

DATASRC_SQLITE_FINDREF looking for referral at '%1'

-Debug information. The SQLite data source is identifying if this domain is -a referral and where it goes. -

DATASRC_SQLITE_FINDREF_BAD_CLASS class mismatch looking for referral ('%1' and '%2')

-The SQLite data source was trying to identify if there's a referral. But -it contains different class than the query was for. -

DATASRC_SQLITE_FIND_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2')

-The SQLite data source was looking up an RRset, but the data source contains -different class than the query was for. -

DATASRC_SQLITE_FIND_NSEC3 looking for NSEC3 in zone '%1' for hash '%2'

-Debug information. We're trying to look up a NSEC3 record in the SQLite data -source. -

DATASRC_SQLITE_FIND_NSEC3_NO_ZONE no such zone '%1'

-The SQLite data source was asked to provide a NSEC3 record for given zone. -But it doesn't contain that zone. -

DATASRC_SQLITE_NEWCONN SQLite3Database is being initialized

-A wrapper object to hold database connection is being initialized. -

DATASRC_SQLITE_OPEN opening SQLite database '%1'

-Debug information. The SQLite data source is loading an SQLite database in -the provided file. -

DATASRC_SQLITE_PREVIOUS looking for name previous to '%1'

-This is a debug message. The name given was not found, so the program -is searching for the next name higher up the hierarchy (e.g. if -www.example.com were queried for and not found, the software searches -for the "previous" name, example.com). -

DATASRC_SQLITE_PREVIOUS_NO_ZONE no zone containing '%1'

-The name given was not found, so the program is searching for the next -name higher up the hierarchy (e.g. if www.example.com were queried -for and not found, the software searches for the "previous" name, -example.com). However, this name is not contained in any zone in the -data source. This is an error since it indicates a problem in the earlier -processing of the query. -

DATASRC_SQLITE_SETUP setting up SQLite database

-The database for SQLite data source was found empty. It is assumed this is the -first run and it is being initialized with current schema. It'll still contain -no data, but it will be ready for use. -

DATASRC_STATIC_CLASS_NOT_CH static data source can handle CH class only

-An error message indicating that a query requesting a RR for a class other -that CH was sent to the static data source (which only handles CH queries). -

DATASRC_STATIC_CREATE creating the static datasource

-Debug information. The static data source (the one holding stuff like -version.bind) is being created. -

DATASRC_STATIC_FIND looking for '%1/%2'

-Debug information. This resource record set is being looked up in the static -data source. -

DATASRC_UNEXPECTED_QUERY_STATE unexpected query state

-This indicates a programming error. An internal task of unknown type was -generated. -

DDNS_CC_SESSION_ERROR error reading from cc channel: %1

-There was a problem reading from the command and control channel. The -most likely cause is that the msgq process is not running. -

DDNS_CC_SESSION_TIMEOUT_ERROR timeout waiting for cc response

-There was a problem reading a response from another module over the -command and control channel. The most likely cause is that the -configuration manager b10-cfgmgr is not running. -

DDNS_CONFIG_ERROR error found in configuration data: %1

-The ddns process encountered an error when installing the configuration at -startup time. Details of the error are included in the log message. -

DDNS_MODULECC_SESSION_ERROR error encountered by configuration/command module: %1

-There was a problem in the lower level module handling configuration and -control commands. This could happen for various reasons, but the most likely -cause is that the configuration database contains a syntax error and ddns -failed to start at initialization. A detailed error message from the module -will also be displayed. -

DDNS_RECEIVED_SHUTDOWN_COMMAND shutdown command received

-The ddns process received a shutdown command from the command channel -and will now shut down. -

DDNS_RUNNING ddns server is running and listening for updates

-The ddns process has successfully started and is now ready to receive commands -and updates. -

DDNS_SHUTDOWN ddns server shutting down

-The ddns process is shutting down. It will no longer listen for new commands -or updates. Any command or update that is being addressed at this moment will -be completed, after which the process will exit. -

DDNS_STOPPED ddns server has stopped

-The ddns process has successfully stopped and is no longer listening for or -handling commands or updates, and will now exit. -

DDNS_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the ddns process. The -process will now shut down. -

DDNS_UNCAUGHT_EXCEPTION uncaught exception of type %1: %2

-The b10-ddns process encountered an uncaught exception and will now shut -down. This is indicative of a programming error and should not happen under -normal circumstances. The exception type and message are printed. -

LIBXFRIN_DIFFERENT_TTL multiple data with different TTLs (%1, %2) on %3/%4/%5. Adjusting %2 -> %1.

-The xfrin module received an update containing multiple rdata changes for the -same RRset. But the TTLs of these don't match each other. As we combine them -together, the latter one gets overwritten to the earlier one in the sequence. -

LIBXFRIN_NO_JOURNAL disabled journaling for updates to %1 on %2

-An attempt was made to create a Diff object with journaling enabled, but -the underlying data source didn't support journaling (while still allowing -updates) and so the created object has it disabled. At a higher level this -means that the updates will be applied to the zone but subsequent IXFR requests -will result in a full zone transfer (i.e., an AXFR-style IXFR). Unless the -overhead of the full transfer is an issue this message can be ignored; -otherwise you may want to check why the journaling wasn't allowed on the -data source and either fix the issue or use a different type of data source. -

LOGIMPL_ABOVE_MAX_DEBUG debug level of %1 is too high and will be set to the maximum of %2

-A message from the interface to the underlying logger implementation reporting -that the debug level (as set by an internally-created string DEBUGn, where n -is an integer, e.g. DEBUG22) is above the maximum allowed value and has -been reduced to that value. The appearance of this message may indicate -a programming error - please submit a bug report. -

LOGIMPL_BAD_DEBUG_STRING debug string '%1' has invalid format

-A message from the interface to the underlying logger implementation -reporting that an internally-created string used to set the debug level -is not of the correct format (it should be of the form DEBUGn, where n -is an integer, e.g. DEBUG22). The appearance of this message indicates -a programming error - please submit a bug report. -

LOGIMPL_BELOW_MIN_DEBUG debug level of %1 is too low and will be set to the minimum of %2

-A message from the interface to the underlying logger implementation reporting -that the debug level (as set by an internally-created string DEBUGn, where n -is an integer, e.g. DEBUG22) is below the minimum allowed value and has -been increased to that value. The appearance of this message may indicate -a programming error - please submit a bug report. -

LOG_BAD_DESTINATION unrecognized log destination: %1

-A logger destination value was given that was not recognized. The -destination should be one of "console", "file", or "syslog". -

LOG_BAD_SEVERITY unrecognized log severity: %1

-A logger severity value was given that was not recognized. The severity -should be one of "DEBUG", "INFO", "WARN", "ERROR", "FATAL" or "NONE". -

LOG_BAD_STREAM bad log console output stream: %1

-Logging has been configured so that output is written to the terminal -(console) but the stream on which it is to be written is not recognised. -Allowed values are "stdout" and "stderr". -

LOG_DUPLICATE_MESSAGE_ID duplicate message ID (%1) in compiled code

-During start-up, BIND 10 detected that the given message identification -had been defined multiple times in the BIND 10 code. This indicates a -programming error; please submit a bug report. -

LOG_DUPLICATE_NAMESPACE line %1: duplicate $NAMESPACE directive found

-When reading a message file, more than one $NAMESPACE directive was found. -(This directive is used to set a C++ namespace when generating header -files during software development.) Such a condition is regarded as an -error and the read will be abandoned. -

LOG_INPUT_OPEN_FAIL unable to open message file %1 for input: %2

-The program was not able to open the specified input message file for -the reason given. -

LOG_INVALID_MESSAGE_ID line %1: invalid message identification '%2'

-An invalid message identification (ID) has been found during the read of -a message file. Message IDs should comprise only alphanumeric characters -and the underscore, and should not start with a digit. -

LOG_NAMESPACE_EXTRA_ARGS line %1: $NAMESPACE directive has too many arguments

-The $NAMESPACE directive in a message file takes a single argument, a -namespace in which all the generated symbol names are placed. This error -is generated when the compiler finds a $NAMESPACE directive with more -than one argument. -

LOG_NAMESPACE_INVALID_ARG line %1: $NAMESPACE directive has an invalid argument ('%2')

-The $NAMESPACE argument in a message file should be a valid C++ namespace. -This message is output if the simple check on the syntax of the string -carried out by the reader fails. -

LOG_NAMESPACE_NO_ARGS line %1: no arguments were given to the $NAMESPACE directive

-The $NAMESPACE directive in a message file takes a single argument, -a C++ namespace in which all the generated symbol names are placed. -This error is generated when the compiler finds a $NAMESPACE directive -with no arguments. -

LOG_NO_MESSAGE_ID line %1: message definition line found without a message ID

-Within a message file, message are defined by lines starting with a "%". -The rest of the line should comprise the message ID and text describing -the message. This error indicates the message compiler found a line in -the message file comprising just the "%" and nothing else. -

LOG_NO_MESSAGE_TEXT line %1: line found containing a message ID ('%2') and no text

-Within a message file, message are defined by lines starting with a "%". -The rest of the line should comprise the message ID and text describing -the message. This error indicates the message compiler found a line -in the message file comprising just the "%" and message identification, -but no text. -

LOG_NO_SUCH_MESSAGE could not replace message text for '%1': no such message

-During start-up a local message file was read. A line with the listed -message identification was found in the file, but the identification is -not one contained in the compiled-in message dictionary. This message -may appear a number of times in the file, once for every such unknown -message identification. -

-There may be several reasons why this message may appear: -

-- The message ID has been mis-spelled in the local message file. -

-- The program outputting the message may not use that particular message -(e.g. it originates in a module not used by the program.) -

-- The local file was written for an earlier version of the BIND 10 software -and the later version no longer generates that message. -

-Whatever the reason, there is no impact on the operation of BIND 10. -

LOG_OPEN_OUTPUT_FAIL unable to open %1 for output: %2

-Originating within the logging code, the program was not able to open -the specified output file for the reason given. -

LOG_PREFIX_EXTRA_ARGS line %1: $PREFIX directive has too many arguments

-Within a message file, the $PREFIX directive takes a single argument, -a prefix to be added to the symbol names when a C++ file is created. -This error is generated when the compiler finds a $PREFIX directive with -more than one argument. -

-Note: the $PREFIX directive is deprecated and will be removed in a future -version of BIND 10. -

LOG_PREFIX_INVALID_ARG line %1: $PREFIX directive has an invalid argument ('%2')

-Within a message file, the $PREFIX directive takes a single argument, -a prefix to be added to the symbol names when a C++ file is created. -As such, it must adhere to restrictions on C++ symbol names (e.g. may -only contain alphanumeric characters or underscores, and may nor start -with a digit). A $PREFIX directive was found with an argument (given -in the message) that violates those restrictions. -

-Note: the $PREFIX directive is deprecated and will be removed in a future -version of BIND 10. -

LOG_READING_LOCAL_FILE reading local message file %1

-This is an informational message output by BIND 10 when it starts to read -a local message file. (A local message file may replace the text of -one of more messages; the ID of the message will not be changed though.) -

LOG_READ_ERROR error reading from message file %1: %2

-The specified error was encountered reading from the named message file. -

LOG_UNRECOGNISED_DIRECTIVE line %1: unrecognised directive '%2'

-Within a message file, a line starting with a dollar symbol was found -(indicating the presence of a directive) but the first word on the line -(shown in the message) was not recognised. -

LOG_WRITE_ERROR error writing to %1: %2

-The specified error was encountered by the message compiler when writing -to the named output file. -

NOTIFY_OUT_DATASRC_ACCESS_FAILURE failed to get access to data source: %1

-notify_out failed to get access to one of configured data sources. -Detailed error is shown in the log message. This can be either a -configuration error or installation setup failure. -

NOTIFY_OUT_DATASRC_ZONE_NOT_FOUND Zone %1 is not found

-notify_out attempted to get slave information of a zone but the zone -isn't found in the expected data source. This shouldn't happen, -because notify_out first identifies a list of available zones before -this process. So this means some critical inconsistency in the data -source or software bug. -

NOTIFY_OUT_INVALID_ADDRESS invalid address %1#%2: %3

-The notify_out library tried to send a notify message to the given -address, but it appears to be an invalid address. The configuration -for secondary nameservers might contain a typographic error, or a -different BIND 10 module has forgotten to validate its data before -sending this module a notify command. As such, this should normally -not happen, and points to an oversight in a different module. -

NOTIFY_OUT_REPLY_BAD_OPCODE bad opcode in notify reply from %1#%2: %3

-The notify_out library sent a notify message to the nameserver at -the given address, but the response did not have the opcode set to -NOTIFY. The opcode in the response is printed. Since there was a -response, no more notifies will be sent to this server for this -notification event. -

NOTIFY_OUT_REPLY_BAD_QID bad QID in notify reply from %1#%2: got %3, should be %4

-The notify_out library sent a notify message to the nameserver at -the given address, but the query id in the response does not match -the one we sent. Since there was a response, no more notifies will -be sent to this server for this notification event. -

NOTIFY_OUT_REPLY_BAD_QUERY_NAME bad query name in notify reply from %1#%2: got %3, should be %4

-The notify_out library sent a notify message to the nameserver at -the given address, but the query name in the response does not match -the one we sent. Since there was a response, no more notifies will -be sent to this server for this notification event. -

NOTIFY_OUT_REPLY_QR_NOT_SET QR flags set to 0 in reply to notify from %1#%2

-The notify_out library sent a notify message to the namesever at the -given address, but the reply did not have the QR bit set to one. -Since there was a response, no more notifies will be sent to this -server for this notification event. -

NOTIFY_OUT_REPLY_UNCAUGHT_EXCEPTION uncaught exception: %1

-There was an uncaught exception in the handling of a notify reply -message, either in the message parser, or while trying to extract data -from the parsed message. The error is printed, and notify_out will -treat the response as a bad message, but this does point to a -programming error, since all exceptions should have been caught -explicitly. Please file a bug report. Since there was a response, -no more notifies will be sent to this server for this notification -event. -

NOTIFY_OUT_RETRY_EXCEEDED notify to %1#%2: number of retries (%3) exceeded

-The maximum number of retries for the notify target has been exceeded. -Either the address of the secondary nameserver is wrong, or it is not -responding. -

NOTIFY_OUT_SENDING_NOTIFY sending notify to %1#%2

-A notify message is sent to the secondary nameserver at the given -address. -

NOTIFY_OUT_SOCKET_ERROR socket error sending notify to %1#%2: %3

-There was a network error while trying to send a notify message to -the given address. The address might be unreachable. The socket -error is printed and should provide more information. -

NOTIFY_OUT_SOCKET_RECV_ERROR socket error reading notify reply from %1#%2: %3

-There was a network error while trying to read a notify reply -message from the given address. The socket error is printed and should -provide more information. -

NOTIFY_OUT_TIMEOUT retry notify to %1#%2

-The notify message to the given address (noted as address#port) has -timed out, and the message will be resent until the max retry limit -is reached. -

NOTIFY_OUT_ZONE_BAD_SOA Zone %1 is invalid in terms of SOA

-This is a warning issued when the notify_out module finds a zone that -doesn't have an SOA RR or has multiple SOA RRs. Notify message won't -be sent to such a zone. -

NOTIFY_OUT_ZONE_NO_NS Zone %1 doesn't have NS RR

-This is a warning issued when the notify_out module finds a zone that -doesn't have an NS RR. Notify message won't be sent to such a zone. -

NSAS_EMPTY_RESPONSE response to query for %1 returned an empty answer section

-The NSAS (nameserver address store - part of the resolver) made a query -for information it needed. The query completed successfully but the -answer section in the response was empty. -

NSAS_ERROR_RESPONSE error response of %1 returned in query for %2

-The NSAS (nameserver address store - part of the resolver) made a query -for information it needed. The query completed successfully but the -RCODE in the response was something other than NOERROR. -

NSAS_FIND_NS_ADDRESS asking resolver to obtain A and AAAA records for %1

-A debug message issued when the NSAS (nameserver address store - part -of the resolver) is making a callback into the resolver to retrieve the -address records for the specified nameserver. -

NSAS_FOUND_ADDRESS found address %1 for %2

-A debug message issued when the NSAS (nameserver address store - part -of the resolver) has retrieved the given address for the specified -nameserver through an external query. -

NSAS_LOOKUP_CANCEL lookup for zone %1 has been canceled

-A debug message issued when an NSAS (nameserver address store - part of -the resolver) lookup for a zone has been canceled. -

NSAS_NS_LOOKUP_FAIL failed to lookup any %1 for %2

-A debug message issued when the NSAS (nameserver address store - part of -the resolver) has been unable to retrieve the specified resource record -for the specified nameserver. This is not necessarily a problem - the -nameserver may be unreachable, in which case the NSAS will try other -nameservers in the zone. -

NSAS_NULL_RESPONSE got null message in success callback for query for %1

-The NSAS (nameserver address store - part of the resolver) made a query -for information it needed. The query completed successfully, but the -message passed to the callback was null. -

-This message indicates an internal error in the NSAS. Please raise a -bug report. -

NSAS_SEARCH_ZONE_NS searching NSAS for nameservers for zone %1

-A debug message output when a call is made to the NSAS (nameserver -address store - part of the resolver) to obtain the nameservers for -the specified zone. -

NSAS_UPDATE_RTT update RTT for %1: was %2 ms, is now %3 ms

-A NSAS (nameserver address store - part of the resolver) debug message -reporting the update of a round-trip time (RTT) for a query made to the -specified nameserver. The RTT has been updated using the value given -and the new RTT is displayed. (The RTT is subject to a calculation that -damps out sudden changes. As a result, the new RTT used by the NSAS in -future decisions of which nameserver to use is not necessarily equal to -the RTT reported.) -

NSAS_WRONG_ANSWER queried for %1 RR of type/class %2/%3, received response %4/%5

-A NSAS (nameserver address store - part of the resolver) made a query for -a resource record of a particular type and class, but instead received -an answer with a different given type and class. -

-This message indicates an internal error in the NSAS. Please raise a -bug report. -

RESLIB_ANSWER answer received in response to query for <%1>

-A debug message reporting that an answer has been received to an upstream -query for the specified question. Previous debug messages will have -indicated the server to which the question was sent. -

RESLIB_CNAME CNAME received in response to query for <%1>

-A debug message recording that CNAME response has been received to an -upstream query for the specified question. Previous debug messages will -have indicated the server to which the question was sent. -

RESLIB_DEEPEST did not find <%1> in cache, deepest delegation found is %2

-A debug message, a cache lookup did not find the specified <name, -class, type> tuple in the cache; instead, the deepest delegation found -is indicated. -

RESLIB_EMPTY_RESPONSE empty response received to query for <%1>

-A debug message, the response to the specified query from an upstream -nameserver did not contain anything in the answer or authority sections, -although in all other respects it was a valid response. A SERVFAIL will -be returned to the system making the original query. -

RESLIB_ERROR_RESPONSE unspecified error received in response to query for <%1>

-A debug message, the response to the specified query to an upstream -nameserver indicated that the response was classified as an erroneous -response, but that the nature of the error cannot be identified. -A SERVFAIL will be returned to the system making the original query. -

RESLIB_EXTRADATA_RESPONSE extra data in response to query for <%1>

-A debug message indicating that the response to the specified query -from an upstream nameserver contained too much data. This can happen if -an ANY query was sent and the answer section in the response contained -multiple RRs with different names. A SERVFAIL will be returned to the -system making the original query. -

RESLIB_FOLLOW_CNAME following CNAME chain to <%1>

-A debug message, a CNAME response was received and another query is -being issued for the <name, class, type> tuple. -

RESLIB_INVALID_NAMECLASS_RESPONSE invalid name or class in response to query for <%1>

-A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) contained either -an answer not matching the query name or an answer having a different -class to that queried for. A SERVFAIL will be returned to the system -making the original query. -

RESLIB_INVALID_QNAME_RESPONSE invalid name or class in response to query for <%1>

-A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) contained a name -in the question section that did not match that of the query. A SERVFAIL -will be returned to the system making the original query. -

RESLIB_INVALID_TYPE_RESPONSE invalid name or class in response to query for <%1>

-A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) contained an -invalid type field. A SERVFAIL will be returned to the system making -the original query. -

RESLIB_LONG_CHAIN CNAME received in response to query for <%1>: CNAME chain length exceeded

-A debug message recording that a CNAME response has been received to an upstream -query for the specified question (Previous debug messages will have indicated -the server to which the question was sent). However, receipt of this CNAME -has meant that the resolver has exceeded the CNAME chain limit (a CNAME chain -is where on CNAME points to another) and so an error is being returned. -

RESLIB_MULTIPLE_CLASS_RESPONSE response to query for <%1> contained multiple RRsets with different classes

-A debug message reporting that the response to an upstream query for -the specified name contained multiple RRsets in the answer and not all -were of the same class. This is a violation of the standard and so a -SERVFAIL will be returned. -

RESLIB_NOTSINGLE_RESPONSE response to query for <%1> was not a response

-A debug message, the response to the specified query from an upstream -nameserver was a CNAME that had mutiple RRs in the RRset. This is -an invalid response according to the standards so a SERVFAIL will be -returned to the system making the original query. -

RESLIB_NOT_ONE_QNAME_RESPONSE not one question in response to query for <%1>

-A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) did not contain -one name in the question section as required by the standard. A SERVFAIL -will be returned to the system making the original query. -

RESLIB_NOT_RESPONSE response to query for <%1> was not a response

-A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) did not have the QR -bit set (thus indicating that the packet was a query, not a response). -A SERVFAIL will be returned to the system making the original query. -

RESLIB_NO_NS_RRSET no NS RRSet in referral response received to query for <%1>

-A debug message, this indicates that a response was received for the specified -query and was categorized as a referral. However, the received message did -not contain any NS RRsets. This may indicate a programming error in the -response classification code. -

RESLIB_NSAS_LOOKUP looking up nameserver for zone %1 in the NSAS

-A debug message, the RunningQuery object is querying the NSAS for the -nameservers for the specified zone. -

RESLIB_NXDOM_NXRR NXDOMAIN/NXRRSET received in response to query for <%1>

-A debug message recording that either a NXDOMAIN or an NXRRSET response has -been received to an upstream query for the specified question. Previous debug -messages will have indicated the server to which the question was sent. -

RESLIB_OPCODE_RESPONSE response to query for <%1> did not have query opcode

-A debug message, the response to the specified query from an upstream -nameserver was a response that did not have the opcode set to that of -a query. According to the standards, this is an invalid response to -the query that was made, so a SERVFAIL will be returned to the system -making the original query. -

RESLIB_PROTOCOL protocol error in answer for %1: %3

-A debug message indicating that a protocol error was received. As there -are no retries left, an error will be reported. -

RESLIB_PROTOCOL_RETRY protocol error in answer for %1: %2 (retries left: %3)

-A debug message indicating that a protocol error was received and that -the resolver is repeating the query to the same nameserver. After this -repeated query, there will be the indicated number of retries left. -

RESLIB_RCODE_ERROR response to query for <%1> returns RCODE of %2

-A debug message, the response to the specified query indicated an error -that is not covered by a specific code path. A SERVFAIL will be returned. -

RESLIB_RECQ_CACHE_FIND found <%1> in the cache (resolve() instance %2)

-This is a debug message and indicates that a RecursiveQuery object found the -the specified <name, class, type> tuple in the cache. The instance number -at the end of the message indicates which of the two resolve() methods has -been called. -

RESLIB_RECQ_CACHE_NO_FIND did not find <%1> in the cache, starting RunningQuery (resolve() instance %2)

-This is a debug message and indicates that the look in the cache made by the -RecursiveQuery::resolve() method did not find an answer, so a new RunningQuery -object has been created to resolve the question. The instance number at -the end of the message indicates which of the two resolve() methods has -been called. -

RESLIB_REFERRAL referral received in response to query for <%1>

-A debug message recording that a referral response has been received to an -upstream query for the specified question. Previous debug messages will -have indicated the server to which the question was sent. -

RESLIB_REFER_ZONE referred to zone %1

-A debug message indicating that the last referral message was to the specified -zone. -

RESLIB_RESOLVE asked to resolve <%1> (resolve() instance %2)

-A debug message, the RecursiveQuery::resolve method has been called to resolve -the specified <name, class, type> tuple. The first action will be to lookup -the specified tuple in the cache. The instance number at the end of the -message indicates which of the two resolve() methods has been called. -

RESLIB_RRSET_FOUND found single RRset in the cache when querying for <%1> (resolve() instance %2)

-A debug message, indicating that when RecursiveQuery::resolve queried the -cache, a single RRset was found which was put in the answer. The instance -number at the end of the message indicates which of the two resolve() -methods has been called. -

RESLIB_RTT round-trip time of last query calculated as %1 ms

-A debug message giving the round-trip time of the last query and response. -

RESLIB_RUNQ_CACHE_FIND found <%1> in the cache

-This is a debug message and indicates that a RunningQuery object found -the specified <name, class, type> tuple in the cache. -

RESLIB_RUNQ_CACHE_LOOKUP looking up up <%1> in the cache

-This is a debug message and indicates that a RunningQuery object has made -a call to its doLookup() method to look up the specified <name, class, type> -tuple, the first action of which will be to examine the cache. -

RESLIB_RUNQ_FAIL failure callback - nameservers are unreachable

-A debug message indicating that a RunningQuery's failure callback has been -called because all nameservers for the zone in question are unreachable. -

RESLIB_RUNQ_SUCCESS success callback - sending query to %1

-A debug message indicating that a RunningQuery's success callback has been -called because a nameserver has been found, and that a query is being sent -to the specified nameserver. -

RESLIB_TCP_TRUNCATED TCP response to query for %1 was truncated

-This is a debug message logged when a response to the specified query to an -upstream nameserver returned a response with the TC (truncation) bit set. This -is treated as an error by the code. -

RESLIB_TEST_SERVER setting test server to %1(%2)

-This is a warning message only generated in unit tests. It indicates -that all upstream queries from the resolver are being routed to the -specified server, regardless of the address of the nameserver to which -the query would normally be routed. If seen during normal operation, -please submit a bug report. -

RESLIB_TEST_UPSTREAM sending upstream query for <%1> to test server at %2

-This is a debug message and should only be seen in unit tests. A query for -the specified <name, class, type> tuple is being sent to a test nameserver -whose address is given in the message. -

RESLIB_TIMEOUT query <%1> to %2 timed out

-A debug message indicating that the specified upstream query has timed out and -there are no retries left. -

RESLIB_TIMEOUT_RETRY query <%1> to %2 timed out, re-trying (retries left: %3)

-A debug message indicating that the specified query has timed out and that -the resolver is repeating the query to the same nameserver. After this -repeated query, there will be the indicated number of retries left. -

RESLIB_TRUNCATED response to query for <%1> was truncated, re-querying over TCP

-A debug message, this indicates that the response to the specified query was -truncated and that the resolver will be re-querying over TCP. There are -various reasons why responses may be truncated, so this message is normal and -gives no cause for concern. -

RESLIB_UPSTREAM sending upstream query for <%1> to %2

-A debug message indicating that a query for the specified <name, class, type> -tuple is being sent to a nameserver whose address is given in the message. -

RESOLVER_AXFR_TCP AXFR request received over TCP

-This is a debug message output when the resolver received a request for -an AXFR (full transfer of a zone) over TCP. Only authoritative servers -are able to handle AXFR requests, so the resolver will return an error -message to the sender with the RCODE set to NOTIMP. -

RESOLVER_AXFR_UDP AXFR request received over UDP

-This is a debug message output when the resolver received a request for -an AXFR (full transfer of a zone) over UDP. Only authoritative servers -are able to handle AXFR requests (and in any case, an AXFR request should -be sent over TCP), so the resolver will return an error message to the -sender with the RCODE set to NOTIMP. -

RESOLVER_CLIENT_TIME_SMALL client timeout of %1 is too small

-During the update of the resolver's configuration parameters, the value -of the client timeout was found to be too small. The configuration -update was abandoned and the parameters were not changed. -

RESOLVER_CONFIG_CHANNEL configuration channel created

-This is a debug message output when the resolver has successfully -established a connection to the configuration channel. -

RESOLVER_CONFIG_ERROR error in configuration: %1

-An error was detected in a configuration update received by the -resolver. This may be in the format of the configuration message (in -which case this is a programming error) or it may be in the data supplied -(in which case it is a user error). The reason for the error, included -in the message, will give more details. The configuration update is -not applied and the resolver parameters were not changed. -

RESOLVER_CONFIG_LOADED configuration loaded

-This is a debug message output when the resolver configuration has been -successfully loaded. -

RESOLVER_CONFIG_UPDATED configuration updated: %1

-This is a debug message output when the resolver configuration is being -updated with the specified information. -

RESOLVER_CREATED main resolver object created

-This is a debug message indicating that the main resolver object has -been created. -

RESOLVER_DNS_MESSAGE_RECEIVED DNS message received: %1

-This is a debug message from the resolver listing the contents of a -received DNS message. -

RESOLVER_DNS_MESSAGE_SENT DNS message of %1 bytes sent: %2

-This is a debug message containing details of the response returned by -the resolver to the querying system. -

RESOLVER_FAILED resolver failed, reason: %1

-This is an error message output when an unhandled exception is caught -by the resolver. After this, the resolver will shut itself down. -Please submit a bug report. -

RESOLVER_FORWARD_ADDRESS setting forward address %1(%2)

-If the resolver is running in forward mode, this message will appear -during startup to list the forward address. If multiple addresses are -specified, it will appear once for each address. -

RESOLVER_FORWARD_QUERY processing forward query

-This is a debug message indicating that a query received by the resolver -has passed a set of checks (message is well-formed, it is allowed by the -ACL, it is a supported opcode, etc.) and is being forwarded to upstream -servers. -

RESOLVER_HEADER_ERROR message received, exception when processing header: %1

-This is a debug message from the resolver noting that an exception -occurred during the processing of a received packet. The packet has -been dropped. -

RESOLVER_IXFR IXFR request received

-This is a debug message indicating that the resolver received a request -for an IXFR (incremental transfer of a zone). Only authoritative servers -are able to handle IXFR requests, so the resolver will return an error -message to the sender with the RCODE set to NOTIMP. -

RESOLVER_LOOKUP_TIME_SMALL lookup timeout of %1 is too small

-During the update of the resolver's configuration parameters, the value -of the lookup timeout was found to be too small. The configuration -update will not be applied. -

RESOLVER_MESSAGE_ERROR error parsing received message: %1 - returning %2

-This is a debug message noting that parsing of the body of a received -message by the resolver failed due to some error (although the parsing of -the header succeeded). The message parameters give a textual description -of the problem and the RCODE returned. -

RESOLVER_NEGATIVE_RETRIES negative number of retries (%1) specified in the configuration

-This error is issued when a resolver configuration update has specified -a negative retry count: only zero or positive values are valid. The -configuration update was abandoned and the parameters were not changed. -

RESOLVER_NON_IN_PACKET non-IN class request received, returning REFUSED message

-This debug message is issued when resolver has received a DNS packet that -was not IN (Internet) class. The resolver cannot handle such packets, -so is returning a REFUSED response to the sender. -

RESOLVER_NORMAL_QUERY processing normal query

-This is a debug message indicating that the query received by the resolver -has passed a set of checks (message is well-formed, it is allowed by the -ACL, it is a supported opcode, etc.) and is being processed by the resolver. -

RESOLVER_NOTIFY_RECEIVED NOTIFY arrived but server is not authoritative

-The resolver has received a NOTIFY message. As the server is not -authoritative it cannot process it, so it returns an error message to -the sender with the RCODE set to NOTAUTH. -

RESOLVER_NOT_ONE_QUESTION query contained %1 questions, exactly one question was expected

-This debug message indicates that the resolver received a query that -contained the number of entries in the question section detailed in -the message. This is a malformed message, as a DNS query must contain -only one question. The resolver will return a message to the sender -with the RCODE set to FORMERR. -

RESOLVER_NO_ROOT_ADDRESS no root addresses available

-A warning message issued during resolver startup, this indicates that -no root addresses have been set. This may be because the resolver will -get them from a priming query. -

RESOLVER_PARSE_ERROR error parsing received message: %1 - returning %2

-This is a debug message noting that the resolver received a message and -the parsing of the body of the message failed due to some non-protocol -related reason (although the parsing of the header succeeded). -The message parameters give a textual description of the problem and -the RCODE returned. -

RESOLVER_PRINT_COMMAND print message command, arguments are: %1

-This debug message is logged when a "print_message" command is received -by the resolver over the command channel. -

RESOLVER_PROTOCOL_ERROR protocol error parsing received message: %1 - returning %2

-This is a debug message noting that the resolver received a message and -the parsing of the body of the message failed due to some protocol error -(although the parsing of the header succeeded). The message parameters -give a textual description of the problem and the RCODE returned. -

RESOLVER_QUERY_ACCEPTED query accepted: '%1/%2/%3' from %4

-This debug message is produced by the resolver when an incoming query -is accepted in terms of the query ACL. The log message shows the query -in the form of <query name>/<query type>/<query class>, and the client -that sends the query in the form of <Source IP address>#<source port>. -

RESOLVER_QUERY_DROPPED query dropped: '%1/%2/%3' from %4

-This is an informational message that indicates an incoming query has -been dropped by the resolver because of the query ACL. Unlike the -RESOLVER_QUERY_REJECTED case, the server does not return any response. -The log message shows the query in the form of <query name>/<query -type>/<query class>, and the client that sends the query in the form of -<Source IP address>#<source port>. -

RESOLVER_QUERY_REJECTED query rejected: '%1/%2/%3' from %4

-This is an informational message that indicates an incoming query has -been rejected by the resolver because of the query ACL. This results -in a response with an RCODE of REFUSED. The log message shows the query -in the form of <query name>/<query type>/<query class>, and the client -that sends the query in the form of <Source IP address>#<source port>. -

RESOLVER_QUERY_SETUP query setup

-This is a debug message noting that the resolver is creating a -RecursiveQuery object. -

RESOLVER_QUERY_SHUTDOWN query shutdown

-This is a debug message noting that the resolver is destroying a -RecursiveQuery object. -

RESOLVER_QUERY_TIME_SMALL query timeout of %1 is too small

-During the update of the resolver's configuration parameters, the value -of the query timeout was found to be too small. The configuration -parameters were not changed. -

RESOLVER_RECEIVED_MESSAGE resolver has received a DNS message

-This is a debug message indicating that the resolver has received a -DNS message. Depending on the debug settings, subsequent log output -will indicate the nature of the message. -

RESOLVER_RECURSIVE running in recursive mode

-This is an informational message that appears at startup noting that -the resolver is running in recursive mode. -

RESOLVER_SERVICE_CREATED service object created

-This debug message is output when resolver creates the main service object -(which handles the received queries). -

RESOLVER_SET_PARAMS query timeout: %1, client timeout: %2, lookup timeout: %3, retry count: %4

-This debug message lists the parameters being set for the resolver. These are: -query timeout: the timeout (in ms) used for queries originated by the resolver -to upstream servers. Client timeout: the interval to resolve a query by -a client: after this time, the resolver sends back a SERVFAIL to the client -whilst continuing to resolve the query. Lookup timeout: the time at which the -resolver gives up trying to resolve a query. Retry count: the number of times -the resolver will retry a query to an upstream server if it gets a timeout. -

-The client and lookup timeouts require a bit more explanation. The -resolution of the client query might require a large number of queries to -upstream nameservers. Even if none of these queries timeout, the total time -taken to perform all the queries may exceed the client timeout. When this -happens, a SERVFAIL is returned to the client, but the resolver continues -with the resolution process; data received is added to the cache. However, -there comes a time - the lookup timeout - when even the resolver gives up. -At this point it will wait for pending upstream queries to complete or -timeout and drop the query. -

RESOLVER_SET_QUERY_ACL query ACL is configured

-This debug message is generated when a new query ACL is configured for -the resolver. -

RESOLVER_SET_ROOT_ADDRESS setting root address %1(%2)

-This message gives the address of one of the root servers used by the -resolver. It is output during startup and may appear multiple times, -once for each root server address. -

RESOLVER_SHUTDOWN resolver shutdown complete

-This informational message is output when the resolver has shut down. -

RESOLVER_STARTED resolver started

-This informational message is output by the resolver when all initialization -has been completed and it is entering its main loop. -

RESOLVER_STARTING starting resolver with command line '%1'

-An informational message, this is output when the resolver starts up. -

RESOLVER_UNEXPECTED_RESPONSE received unexpected response, ignoring

-This is a debug message noting that the resolver received a DNS response -packet on the port on which is it listening for queries. The packet -has been ignored. -

RESOLVER_UNSUPPORTED_OPCODE opcode %1 not supported by the resolver

-This is debug message output when the resolver received a message with an -unsupported opcode (it can only process QUERY opcodes). It will return -a message to the sender with the RCODE set to NOTIMP. -

SOCKETREQUESTOR_CREATED Socket requestor created

-Debug message. A socket requesor (client of the socket creator) is created -for the corresponding application. Normally this should happen at most -one time throughout the lifetime of the application. -

SOCKETREQUESTOR_DESTROYED Socket requestor destoryed

-Debug message. The socket requestor created at SOCKETREQUESTOR_CREATED -has been destroyed. This event is generally unexpected other than in -test cases. -

SOCKETREQUESTOR_GETSOCKET Received a %1 socket for [%2]:%3, FD=%4, token=%5, path=%6

-Debug message. The socket requestor for the corresponding application -has requested a socket for a set of address, port and protocol (shown -in the log message) and successfully got it from the creator. The -corresponding file descriptor and the associated "token" (an internal -ID used between the creator and requestor) are shown in the log -message. -

SOCKETREQUESTOR_RELEASESOCKET Released a socket of token %1

-Debug message. The socket requestor has released a socket passed by -the creator. The associated token of the socket is shown in the -log message. If the corresponding SOCKETREQUESTOR_GETSOCKET was logged -more detailed information of the socket can be identified by matching -the token. -

SRVCOMM_ADDRESSES_NOT_LIST the address and port specification is not a list in %1

-This points to an error in configuration. What was supposed to be a list of -IP address - port pairs isn't a list at all but something else. -

SRVCOMM_ADDRESS_FAIL failed to listen on addresses (%1)

-The server failed to bind to one of the address/port pair it should according -to configuration, for reason listed in the message (usually because that pair -is already used by other service or missing privileges). The server will try -to recover and bind the address/port pairs it was listening to before (if any). -

SRVCOMM_ADDRESS_MISSING address specification is missing "address" or "port" element in %1

-This points to an error in configuration. An address specification in the -configuration is missing either an address or port and so cannot be used. The -specification causing the error is given in the message. -

SRVCOMM_ADDRESS_TYPE address specification type is invalid in %1

-This points to an error in configuration. An address specification in the -configuration malformed. The specification causing the error is given in the -message. A valid specification contains an address part (which must be a string -and must represent a valid IPv4 or IPv6 address) and port (which must be an -integer in the range valid for TCP/UDP ports on your system). -

SRVCOMM_ADDRESS_UNRECOVERABLE failed to recover original addresses also (%1)

-The recovery of old addresses after SRVCOMM_ADDRESS_FAIL also failed for -the reason listed. -

-The condition indicates problems with the server and/or the system on -which it is running. The server will continue running to allow -reconfiguration, but will not be listening on any address or port until -an administrator does so. -

SRVCOMM_ADDRESS_VALUE address to set: %1#%2

-Debug message. This lists one address and port value of the set of -addresses we are going to listen on (eg. there will be one log message -per pair). This appears only after SRVCOMM_SET_LISTEN, but might -be hidden, as it has higher debug level. -

SRVCOMM_KEYS_DEINIT deinitializing TSIG keyring

-Debug message indicating that the server is deinitializing the TSIG keyring. -

SRVCOMM_KEYS_INIT initializing TSIG keyring

-Debug message indicating that the server is initializing the global TSIG -keyring. This should be seen only at server start. -

SRVCOMM_KEYS_UPDATE updating TSIG keyring

-Debug message indicating new keyring is being loaded from configuration (either -on startup or as a result of configuration update). -

SRVCOMM_PORT_RANGE port out of valid range (%1 in %2)

-This points to an error in configuration. The port in an address -specification is outside the valid range of 0 to 65535. -

SRVCOMM_SET_LISTEN setting addresses to listen to

-Debug message, noting that the server is about to start listening on a -different set of IP addresses and ports than before. -

STATHTTPD_BAD_OPTION_VALUE bad command line argument: %1

-The stats-httpd module was called with a bad command-line argument -and will not start. -

STATHTTPD_CC_SESSION_ERROR error connecting to message bus: %1

-The stats-httpd module was unable to connect to the BIND 10 command -and control bus. A likely problem is that the message bus daemon -(b10-msgq) is not running. The stats-httpd module will now shut down. -

STATHTTPD_CLOSING closing %1#%2

-The stats-httpd daemon will stop listening for requests on the given -address and port number. -

STATHTTPD_CLOSING_CC_SESSION stopping cc session

-Debug message indicating that the stats-httpd module is disconnecting -from the command and control bus. -

STATHTTPD_HANDLE_CONFIG reading configuration: %1

-The stats-httpd daemon has received new configuration data and will now -process it. The (changed) data is printed. -

STATHTTPD_RECEIVED_SHUTDOWN_COMMAND shutdown command received

-A shutdown command was sent to the stats-httpd module, and it will -now shut down. -

STATHTTPD_RECEIVED_STATUS_COMMAND received command to return status

-A status command was sent to the stats-httpd module, and it will -respond with 'Stats Httpd is up.' and its PID. -

STATHTTPD_RECEIVED_UNKNOWN_COMMAND received unknown command: %1

-An unknown command has been sent to the stats-httpd module. The -stats-httpd module will respond with an error, and the command will -be ignored. -

STATHTTPD_SERVER_DATAERROR HTTP server data error: %1

-An internal error occurred while handling an HTTP request. An HTTP 404 -response will be sent back, and the specific error is printed. This -is an error condition that likely points the specified data -corresponding to the requested URI is incorrect. -

STATHTTPD_SERVER_ERROR HTTP server error: %1

-An internal error occurred while handling an HTTP request. An HTTP 500 -response will be sent back, and the specific error is printed. This -is an error condition that likely points to a module that is not -responding correctly to statistic requests. -

STATHTTPD_SERVER_INIT_ERROR HTTP server initialization error: %1

-There was a problem initializing the HTTP server in the stats-httpd -module upon receiving its configuration data. The most likely cause -is a port binding problem or a bad configuration value. The specific -error is printed in the message. The new configuration is ignored, -and an error is sent back. -

STATHTTPD_SHUTDOWN shutting down

-The stats-httpd daemon is shutting down. -

STATHTTPD_STARTED listening on %1#%2

-The stats-httpd daemon will now start listening for requests on the -given address and port number. -

STATHTTPD_STARTING_CC_SESSION starting cc session

-Debug message indicating that the stats-httpd module is connecting to -the command and control bus. -

STATHTTPD_START_SERVER_INIT_ERROR HTTP server initialization error: %1

-There was a problem initializing the HTTP server in the stats-httpd -module upon startup. The most likely cause is that it was not able -to bind to the listening port. The specific error is printed, and the -module will shut down. -

STATHTTPD_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the stats-httpd -daemon. The daemon will now shut down. -

STATHTTPD_UNKNOWN_CONFIG_ITEM unknown configuration item: %1

-The stats-httpd daemon received a configuration update from the -configuration manager. However, one of the items in the -configuration is unknown. The new configuration is ignored, and an -error is sent back. As possible cause is that there was an upgrade -problem, and the stats-httpd version is out of sync with the rest of -the system. -

STATS_BAD_OPTION_VALUE bad command line argument: %1

-The stats module was called with a bad command-line argument and will -not start. -

STATS_CC_SESSION_ERROR error connecting to message bus: %1

-The stats module was unable to connect to the BIND 10 command and -control bus. A likely problem is that the message bus daemon -(b10-msgq) is not running. The stats module will now shut down. -

STATS_RECEIVED_NEW_CONFIG received new configuration: %1

-This debug message is printed when the stats module has received a -configuration update from the configuration manager. -

STATS_RECEIVED_SHOWSCHEMA_ALL_COMMAND received command to show all statistics schema

-The stats module received a command to show all statistics schemas of all modules. -

STATS_RECEIVED_SHOWSCHEMA_NAME_COMMAND received command to show statistics schema for %1

-The stats module received a command to show the specified statistics schema of the specified module. -

STATS_RECEIVED_SHOW_ALL_COMMAND received command to show all statistics

-The stats module received a command to show all statistics that it has -collected. -

STATS_RECEIVED_SHOW_NAME_COMMAND received command to show statistics for %1

-The stats module received a command to show the statistics that it has -collected for the given item. -

STATS_RECEIVED_SHUTDOWN_COMMAND shutdown command received

-A shutdown command was sent to the stats module and it will now shut down. -

STATS_RECEIVED_STATUS_COMMAND received command to return status

-A status command was sent to the stats module. It will return a -response indicating that it is running normally. -

STATS_RECEIVED_UNKNOWN_COMMAND received unknown command: %1

-An unknown command has been sent to the stats module. The stats module -will respond with an error and the command will be ignored. -

STATS_SEND_REQUEST_BOSS requesting boss to send statistics

-This debug message is printed when a request is sent to the boss module -to send its data to the stats module. -

STATS_STARTING starting

-The stats module will be now starting. -

STATS_START_ERROR stats module error: %1

-An internal error occurred while starting the stats module. The stats -module will be now shutting down. -

STATS_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the stats module. The -daemon will now shut down. -

STATS_UNKNOWN_COMMAND_IN_SPEC unknown command in specification file: %1

-The specification file for the stats module contains a command that -is unknown in the implementation. The most likely cause is an -installation problem, where the specification file stats.spec is -from a different version of BIND 10 than the stats module itself. -Please check your installation. -

XFRIN_AXFR_INCONSISTENT_SOA AXFR SOAs are inconsistent for %1: %2 expected, %3 received

-The serial fields of the first and last SOAs of AXFR (including AXFR-style -IXFR) are not the same. According to RFC 5936 these two SOAs must be the -"same" (not only for the serial), but it is still not clear what the -receiver should do if this condition does not hold. There was a discussion -about this at the IETF dnsext wg: -http://www.ietf.org/mail-archive/web/dnsext/current/msg07908.html -and the general feeling seems that it would be better to reject the -transfer if a mismatch is detected. On the other hand, also as noted -in that email thread, neither BIND 9 nor NSD performs any comparison -on the SOAs. For now, we only check the serials (ignoring other fields) -and only leave a warning log message when a mismatch is found. If it -turns out to happen with a real world primary server implementation -and that server actually feeds broken data (e.g. mixed versions of -zone), we can consider a stricter action. -

XFRIN_BAD_MASTER_ADDR_FORMAT bad format for master address: %1

-The given master address is not a valid IP address. -

XFRIN_BAD_MASTER_PORT_FORMAT bad format for master port: %1

-The master port as read from the configuration is not a valid port number. -

XFRIN_BAD_TSIG_KEY_STRING bad TSIG key string: %1

-The TSIG key string as read from the configuration does not represent -a valid TSIG key. -

XFRIN_BAD_ZONE_CLASS Invalid zone class: %1

-The zone class as read from the configuration is not a valid DNS class. -

XFRIN_CC_SESSION_ERROR error reading from cc channel: %1

-There was a problem reading from the command and control channel. The -most likely cause is that xfrin the msgq daemon is not running. -

XFRIN_COMMAND_ERROR error while executing command '%1': %2

-There was an error while the given command was being processed. The -error is given in the log message. -

XFRIN_CONNECT_MASTER error connecting to master at %1: %2

-There was an error opening a connection to the master. The error is -shown in the log message. -

XFRIN_GOT_INCREMENTAL_RESP got incremental response for %1

-In an attempt of IXFR processing, the begenning SOA of the first difference -(following the initial SOA that specified the final SOA for all the -differences) was found. This means a connection for xfrin tried IXFR -and really aot a response for incremental updates. -

XFRIN_GOT_NONINCREMENTAL_RESP got nonincremental response for %1

-Non incremental transfer was detected at the "first data" of a transfer, -which is the RR following the initial SOA. Non incremental transfer is -either AXFR or AXFR-style IXFR. In the latter case, it means that -in a response to IXFR query the first data is not SOA or its SOA serial -is not equal to the requested SOA serial. -

XFRIN_IMPORT_DNS error importing python DNS module: %1

-There was an error importing the python DNS module pydnspp. The most -likely cause is a PYTHONPATH problem. -

XFRIN_IXFR_UPTODATE IXFR requested serial for %1 is %2, master has %3, not updating

-The first SOA record in an IXFR response indicates the zone's serial -at the primary server is not newer than the client's. This is -basically unexpected event because normally the client first checks -the SOA serial by an SOA query, but can still happen if the transfer -is manually invoked or (although unlikely) there is a rapid change at -the primary server between the SOA and IXFR queries. The client -implementation confirms the whole response is this single SOA, and -aborts the transfer just like a successful case. -

XFRIN_MSGQ_SEND_ERROR error while contacting %1 and %2

-There was a problem sending a message to the xfrout module or the -zone manager. This most likely means that the msgq daemon has quit or -was killed. -

XFRIN_MSGQ_SEND_ERROR_ZONE_MANAGER error while contacting %1

-There was a problem sending a message to the zone manager. This most -likely means that the msgq daemon has quit or was killed. -

XFRIN_NOTIFY_UNKNOWN_MASTER got notification to retransfer zone %1 from %2, expected %3

-The system received a notify for the given zone, but the address it came -from does not match the master address in the Xfrin configuration. The notify -is ignored. This may indicate that the configuration for the master is wrong, -that a wrong machine is sending notifies, or that fake notifies are being sent. -

XFRIN_RETRANSFER_UNKNOWN_ZONE got notification to retransfer unknown zone %1

-There was an internal command to retransfer the given zone, but the -zone is not known to the system. This may indicate that the configuration -for xfrin is incomplete, or there was a typographical error in the -zone name in the configuration. -

XFRIN_STARTING starting resolver with command line '%1'

-An informational message, this is output when the resolver starts up. -

XFRIN_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the xfrin daemon. The -daemon will now shut down. -

XFRIN_UNKNOWN_ERROR unknown error: %1

-An uncaught exception was raised while running the xfrin daemon. The -exception message is printed in the log message. -

XFRIN_XFR_OTHER_FAILURE %1 transfer of zone %2 failed: %3

-The XFR transfer for the given zone has failed due to a problem outside -of the xfrin module. Possible reasons are a broken DNS message or failure -in database connection. The error is shown in the log message. -

XFRIN_XFR_PROCESS_FAILURE %1 transfer of zone %2/%3 failed: %4

-An XFR session failed outside the main protocol handling. This -includes an error at the data source level at the initialization -phase, unexpected failure in the network connection setup to the -master server, or even more unexpected failure due to unlikely events -such as memory allocation failure. Details of the error are shown in -the log message. In general, these errors are not really expected -ones, and indicate an installation error or a program bug. The -session handler thread tries to clean up all intermediate resources -even on these errors, but it may be incomplete. So, if this log -message continuously appears, system resource consumption should be -checked, and you may even want to disable the corresponding transfers. -You may also want to file a bug report if this message appears so -often. -

XFRIN_XFR_TRANSFER_FAILURE %1 transfer of zone %2 with %3 failed: %4

-The XFR transfer for the given zone has failed due to an internal error. -The error is shown in the log message. -

XFRIN_XFR_TRANSFER_FALLBACK falling back from IXFR to AXFR for %1

-The IXFR transfer of the given zone failed. This might happen in many cases, -such that the remote server doesn't support IXFR, we don't have the SOA record -(or the zone at all), we are out of sync, etc. In many of these situations, -AXFR could still work. Therefore we try that one in case it helps. -

XFRIN_XFR_TRANSFER_PROTOCOL_ERROR %1 transfer of zone %2 with %3 failed: %4

-The XFR transfer for the given zone has failed due to a protocol -error, such as an unexpected response from the primary server. The -error is shown in the log message. It may be because the primary -server implementation is broken or (although less likely) there was -some attack attempt, but it can also happen due to configuration -mismatch such as the remote server does not have authority for the -zone any more but the local configuration hasn't been updated. So it -is recommended to check the primary server configuration. -

XFRIN_XFR_TRANSFER_STARTED %1 transfer of zone %2 started

-A connection to the master server has been made, the serial value in -the SOA record has been checked, and a zone transfer has been started. -

XFRIN_XFR_TRANSFER_SUCCESS %1 transfer of zone %2 succeeded

-The XFR transfer of the given zone was successfully completed. -

XFRIN_ZONE_CREATED Zone %1 not found in the given data source, newly created

-On starting an xfrin session, it is identified that the zone to be -transferred is not found in the data source. This can happen if a -secondary DNS server first tries to perform AXFR from a primary server -without creating the zone image beforehand (e.g. by b10-loadzone). As -of this writing the xfrin process provides backward compatible -behavior to previous versions: creating a new one in the data source -not to surprise existing users too much. This is probably not a good -idea, however, in terms of who should be responsible for managing -zones at a higher level. In future it is more likely that a separate -zone management framework is provided, and the situation where the -given zone isn't found in xfrout will be treated as an error. -

XFRIN_ZONE_MULTIPLE_SOA Zone %1 has %2 SOA RRs

-On starting an xfrin session, it is identified that the zone to be -transferred has multiple SOA RRs. Such a zone is broken, but could be -accidentally configured especially in a data source using "non -captive" backend database. The implementation ignores entire SOA RRs -and tries to continue processing as if the zone were empty. This -means subsequent AXFR can succeed and possibly replace the zone with -valid content, but an IXFR attempt will fail. -

XFRIN_ZONE_NO_SOA Zone %1 does not have SOA

-On starting an xfrin session, it is identified that the zone to be -transferred does not have an SOA RR in the data source. This is not -necessarily an error; if a secondary DNS server first tries to perform -transfer from a primary server, the zone can be empty, and therefore -doesn't have an SOA. Subsequent AXFR will fill in the zone; if the -attempt is IXFR it will fail in query creation. -

XFRIN_ZONE_SERIAL_AHEAD Serial number (%1) for %2 received from master %3 < ours (%4)

-The response to an SOA query prior to xfr indicated that the zone's -SOA serial at the primary server is smaller than that of the xfrin -client. This is not necessarily an error especially if that -particular primary server is another secondary server which hasn't got -the latest version of the zone. But if the primary server is known to -be the real source of the zone, some unexpected inconsistency may have -happened, and you may want to take a closer look. In this case xfrin -doesn't perform subsequent zone transfer. -

XFROUT_BAD_TSIG_KEY_STRING bad TSIG key string: %1

-The TSIG key string as read from the configuration does not represent -a valid TSIG key. -

XFROUT_CC_SESSION_ERROR error reading from cc channel: %1

-There was a problem reading from the command and control channel. The -most likely cause is that the msgq daemon is not running. -

XFROUT_CC_SESSION_TIMEOUT_ERROR timeout waiting for cc response

-There was a problem reading a response from another module over the -command and control channel. The most likely cause is that the -configuration manager b10-cfgmgr is not running. -

XFROUT_CONFIG_ERROR error found in configuration data: %1

-The xfrout process encountered an error when installing the configuration at -startup time. Details of the error are included in the log message. -

XFROUT_FETCH_REQUEST_ERROR socket error while fetching a request from the auth daemon

-There was a socket error while contacting the b10-auth daemon to -fetch a transfer request. The auth daemon may have shutdown. -

XFROUT_HANDLE_QUERY_ERROR error while handling query: %1

-There was a general error handling an xfrout query. The error is shown -in the message. In principle this error should not appear, and points -to an oversight catching exceptions in the right place. However, to -ensure the daemon keeps running, this error is caught and reported. -

XFROUT_IMPORT error importing python module: %1

-There was an error importing a python module. One of the modules needed -by xfrout could not be found. This suggests that either some libraries -are missing on the system, or the PYTHONPATH variable is not correct. -The specific place where this library needs to be depends on your -system and your specific installation. -

XFROUT_IXFR_MULTIPLE_SOA IXFR client %1: authority section has multiple SOAs

-An IXFR request was received with more than one SOA RRs in the authority -section. The xfrout daemon rejects the request with an RCODE of -FORMERR. -

XFROUT_IXFR_NO_JOURNAL_SUPPORT IXFR client %1, %2: journaling not supported in the data source, falling back to AXFR

-An IXFR request was received but the underlying data source did -not support journaling. The xfrout daemon fell back to AXFR-style -IXFR. -

XFROUT_IXFR_NO_SOA IXFR client %1: missing SOA

-An IXFR request was received with no SOA RR in the authority section. -The xfrout daemon rejects the request with an RCODE of FORMERR. -

XFROUT_IXFR_NO_VERSION IXFR client %1, %2: version (%3 to %4) not in journal, falling back to AXFR

-An IXFR request was received, but the requested range of differences -were not found in the data source. The xfrout daemon fell back to -AXFR-style IXFR. -

XFROUT_IXFR_NO_ZONE IXFR client %1, %2: zone not found with journal

-The requested zone in IXFR was not found in the data source -even though the xfrout daemon sucessfully found the SOA RR of the zone -in the data source. This can happen if the administrator removed the -zone from the data source within the small duration between these -operations, but it's more likely to be a bug or broken data source. -Unless you know why this message was logged, and especially if it -happens often, it's advisable to check whether the data source is -valid for this zone. The xfrout daemon considers it a possible, -though unlikely, event, and returns a response with an RCODE of -NOTAUTH. -

XFROUT_IXFR_UPTODATE IXFR client %1, %2: client version is new enough (theirs=%3, ours=%4)

-An IXFR request was received, but the client's SOA version is the same as -or newer than that of the server. The xfrout server responds to the -request with the answer section being just one SOA of that version. -Note: as of this wrting the 'newer version' cannot be identified due to -the lack of support for the serial number arithmetic. This will soon -be implemented. -

XFROUT_MODULECC_SESSION_ERROR error encountered by configuration/command module: %1

-There was a problem in the lower level module handling configuration and -control commands. This could happen for various reasons, but the most likely -cause is that the configuration database contains a syntax error and xfrout -failed to start at initialization. A detailed error message from the module -will also be displayed. -

XFROUT_NEW_CONFIG Update xfrout configuration

-New configuration settings have been sent from the configuration -manager. The xfrout daemon will now apply them. -

XFROUT_NEW_CONFIG_DONE Update xfrout configuration done

-The xfrout daemon is now done reading the new configuration settings -received from the configuration manager. -

XFROUT_NOTIFY_COMMAND received command to send notifies for %1/%2

-The xfrout daemon received a command on the command channel that -NOTIFY packets should be sent for the given zone. -

XFROUT_PARSE_QUERY_ERROR error parsing query: %1

-There was a parse error while reading an incoming query. The parse -error is shown in the log message. A remote client sent a packet we -do not understand or support. The xfrout request will be ignored. -In general, this should only occur for unexpected problems like -memory allocation failures, as the query should already have been -parsed by the b10-auth daemon, before it was passed here. -

XFROUT_PROCESS_REQUEST_ERROR error processing transfer request: %2

-There was an error processing a transfer request. The error is included -in the log message, but at this point no specific information other -than that could be given. This points to incomplete exception handling -in the code. -

XFROUT_QUERY_DROPPED %1 client %2: request to transfer %3 dropped

-The xfrout process silently dropped a request to transfer zone to -given host. This is required by the ACLs. The %2 represents the IP -address and port of the peer requesting the transfer, and the %3 -represents the zone name and class. -

XFROUT_QUERY_QUOTA_EXCCEEDED %1 client %2: request denied due to quota (%3)

-The xfr request was rejected because the server was already handling -the maximum number of allowable transfers as specified in the transfers_out -configuration parameter, which is also shown in the log message. The -request was immediately responded and terminated with an RCODE of REFUSED. -This can happen for a busy xfrout server, and you may want to increase -this parameter; if the server is being too busy due to requests from -unexpected clients you may want to restrict the legitimate clients -with ACL. -

XFROUT_QUERY_REJECTED %1 client %2: request to transfer %3 rejected

-The xfrout process rejected (by REFUSED rcode) a request to transfer zone to -given host. This is because of ACLs. The %2 represents the IP -address and port of the peer requesting the transfer, and the %3 -represents the zone name and class. -

XFROUT_RECEIVED_SHUTDOWN_COMMAND shutdown command received

-The xfrout daemon received a shutdown command from the command channel -and will now shut down. -

XFROUT_RECEIVE_FILE_DESCRIPTOR_ERROR error receiving the file descriptor for an XFR connection

-There was an error receiving the file descriptor for the transfer -request. Normally, the request is received by b10-auth, and passed on -to the xfrout daemon, so it can answer directly. However, there was a -problem receiving this file descriptor. The request will be ignored. -

XFROUT_REMOVE_OLD_UNIX_SOCKET_FILE_ERROR error removing unix socket file %1: %2

-The unix socket file xfrout needs for contact with the auth daemon -already exists, and needs to be removed first, but there is a problem -removing it. It is likely that we do not have permission to remove -this file. The specific error is show in the log message. The xfrout -daemon will shut down. -

XFROUT_REMOVE_UNIX_SOCKET_FILE_ERROR error clearing unix socket file %1: %2

-When shutting down, the xfrout daemon tried to clear the unix socket -file used for communication with the auth daemon. It failed to remove -the file. The reason for the failure is given in the error message. -

XFROUT_SOCKET_SELECT_ERROR error while calling select() on request socket: %1

-There was an error while calling select() on the socket that informs -the xfrout daemon that a new xfrout request has arrived. This should -be a result of rare local error such as memory allocation failure and -shouldn't happen under normal conditions. The error is included in the -log message. -

XFROUT_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down

-There was a keyboard interrupt signal to stop the xfrout daemon. The -daemon will now shut down. -

XFROUT_STOPPING the xfrout daemon is shutting down

-The current transfer is aborted, as the xfrout daemon is shutting down. -

XFROUT_UNIX_SOCKET_FILE_IN_USE another xfrout process seems to be using the unix socket file %1

-While starting up, the xfrout daemon tried to clear the unix domain -socket needed for contacting the b10-auth daemon to pass requests -on, but the file is in use. The most likely cause is that another -xfrout daemon process is still running. This xfrout daemon (the one -printing this message) will not start. -

XFROUT_XFR_TRANSFER_CHECK_ERROR %1 client %2: check for transfer of %3 failed: %4

-Pre-response check for an incomding XFR request failed unexpectedly. -The most likely cause of this is that some low level error in the data -source, but it may also be other general (more unlikely) errors such -as memory shortage. Some detail of the error is also included in the -message. The xfrout server tries to return a SERVFAIL response in this case. -

XFROUT_XFR_TRANSFER_DONE %1 client %2: transfer of %3 complete

-The transfer of the given zone has been completed successfully, or was -aborted due to a shutdown event. -

XFROUT_XFR_TRANSFER_ERROR %1 client %2: error transferring zone %3: %4

-An uncaught exception was encountered while sending the response to -an AXFR query. The error message of the exception is included in the -log message, but this error most likely points to incomplete exception -handling in the code. -

XFROUT_XFR_TRANSFER_FAILED %1 client %2: transfer of %3 failed, rcode: %4

-A transfer out for the given zone failed. An error response is sent -to the client. The given rcode is the rcode that is set in the error -response. This is either NOTAUTH (we are not authoritative for the -zone), SERVFAIL (our internal database is missing the SOA record for -the zone), or REFUSED (the limit of simultaneous outgoing AXFR -transfers, as specified by the configuration value -Xfrout/max_transfers_out, has been reached). -

XFROUT_XFR_TRANSFER_STARTED %1 client %2: transfer of zone %3 has started

-A transfer out of the given zone has started. -

ZONEMGR_CCSESSION_ERROR command channel session error: %1

-An error was encountered on the command channel. The message indicates -the nature of the error. -

ZONEMGR_JITTER_TOO_BIG refresh_jitter is too big, setting to 0.5

-The value specified in the configuration for the refresh jitter is too large -so its value has been set to the maximum of 0.5. -

ZONEMGR_KEYBOARD_INTERRUPT exiting zonemgr process as result of keyboard interrupt

-An informational message output when the zone manager was being run at a -terminal and it was terminated via a keyboard interrupt signal. -

ZONEMGR_LOAD_ZONE loading zone %1 (class %2)

-This is a debug message indicating that the zone of the specified class -is being loaded. -

ZONEMGR_NO_MASTER_ADDRESS internal BIND 10 command did not contain address of master

-A command received by the zone manager from the Auth module did not -contain the address of the master server from which a NOTIFY message -was received. This may be due to an internal programming error; please -submit a bug report. -

ZONEMGR_NO_SOA zone %1 (class %2) does not have an SOA record

-When loading the named zone of the specified class the zone manager -discovered that the data did not contain an SOA record. The load has -been abandoned. -

ZONEMGR_NO_TIMER_THREAD trying to stop zone timer thread but it is not running

-An attempt was made to stop the timer thread (used to track when zones -should be refreshed) but it was not running. This may indicate an -internal program error. Please submit a bug report. -

ZONEMGR_NO_ZONE_CLASS internal BIND 10 command did not contain class of zone

-A command received by the zone manager from another BIND 10 module did -not contain the class of the zone on which the zone manager should act. -This may be due to an internal programming error; please submit a -bug report. -

ZONEMGR_NO_ZONE_NAME internal BIND 10 command did not contain name of zone

-A command received by the zone manager from another BIND 10 module did -not contain the name of the zone on which the zone manager should act. -This may be due to an internal programming error; please submit a -bug report. -

ZONEMGR_RECEIVE_NOTIFY received NOTIFY command for zone %1 (class %2)

-This is a debug message indicating that the zone manager has received a -NOTIFY command over the command channel. The command is sent by the Auth -process when it is acting as a slave server for the zone and causes the -zone manager to record the master server for the zone and start a timer; -when the timer expires, the master will be polled to see if it contains -new data. -

ZONEMGR_RECEIVE_SHUTDOWN received SHUTDOWN command

-This is a debug message indicating that the zone manager has received -a SHUTDOWN command over the command channel from the Boss process. -It will act on this command and shut down. -

ZONEMGR_RECEIVE_UNKNOWN received unknown command '%1'

-This is a warning message indicating that the zone manager has received -the stated command over the command channel. The command is not known -to the zone manager and although the command is ignored, its receipt -may indicate an internal error. Please submit a bug report. -

ZONEMGR_RECEIVE_XFRIN_FAILED received XFRIN FAILED command for zone %1 (class %2)

-This is a debug message indicating that the zone manager has received -an XFRIN FAILED command over the command channel. The command is sent -by the Xfrin process when a transfer of zone data into the system has -failed, and causes the zone manager to schedule another transfer attempt. -

ZONEMGR_RECEIVE_XFRIN_SUCCESS received XFRIN SUCCESS command for zone %1 (class %2)

-This is a debug message indicating that the zone manager has received -an XFRIN SUCCESS command over the command channel. The command is sent -by the Xfrin process when the transfer of zone data into the system has -succeeded, and causes the data to be loaded and served by BIND 10. -

ZONEMGR_REFRESH_ZONE refreshing zone %1 (class %2)

-The zone manager is refreshing the named zone of the specified class -with updated information. -

ZONEMGR_SELECT_ERROR error with select(): %1

-An attempt to wait for input from a socket failed. The failing operation -is a call to the operating system's select() function, which failed for -the given reason. -

ZONEMGR_SEND_FAIL failed to send command to %1, session has been closed

-The zone manager attempted to send a command to the named BIND 10 module, -but the send failed. The session between the modules has been closed. -

ZONEMGR_SESSION_ERROR unable to establish session to command channel daemon

-The zonemgr process was not able to be started because it could not -connect to the command channel daemon. The most usual cause of this -problem is that the daemon is not running. -

ZONEMGR_SESSION_TIMEOUT timeout on session to command channel daemon

-The zonemgr process was not able to be started because it timed out when -connecting to the command channel daemon. The most usual cause of this -problem is that the daemon is not running. -

ZONEMGR_SHUTDOWN zone manager has shut down

-A debug message, output when the zone manager has shut down completely. -

ZONEMGR_STARTING zone manager starting

-A debug message output when the zone manager starts up. -

ZONEMGR_TIMER_THREAD_RUNNING trying to start timer thread but one is already running

-This message is issued when an attempt is made to start the timer -thread (which keeps track of when zones need a refresh) but one is -already running. It indicates either an error in the program logic or -a problem with stopping a previous instance of the timer. Please submit -a bug report. -

ZONEMGR_UNKNOWN_ZONE_FAIL zone %1 (class %2) is not known to the zone manager

-An XFRIN operation has failed but the zone that was the subject of the -operation is not being managed by the zone manager. This may indicate -an error in the program (as the operation should not have been initiated -if this were the case). Please submit a bug report. -

ZONEMGR_UNKNOWN_ZONE_NOTIFIED notified zone %1 (class %2) is not known to the zone manager

-A NOTIFY was received but the zone that was the subject of the operation -is not being managed by the zone manager. This may indicate an error -in the program (as the operation should not have been initiated if this -were the case). Please submit a bug report. -

ZONEMGR_UNKNOWN_ZONE_SUCCESS zone %1 (class %2) is not known to the zone manager

-An XFRIN operation has succeeded but the zone received is not being -managed by the zone manager. This may indicate an error in the program -(as the operation should not have been initiated if this were the case). -Please submit a bug report. -

-

diff --git a/doc/guide/bind10-messages.xml b/doc/guide/bind10-messages.xml deleted file mode 100644 index c085cb14b9..0000000000 --- a/doc/guide/bind10-messages.xml +++ /dev/null @@ -1,5896 +0,0 @@ - - - -%version; -]> - - - - - - BIND 10 Messages Manual - - - 2011-2012Internet Systems Consortium, Inc. - - - - BIND 10 is a Domain Name System (DNS) suite managed by - Internet Systems Consortium (ISC). It includes DNS libraries - and modular components for controlling authoritative and - recursive DNS servers. - - - This is the messages manual for BIND 10 version &__VERSION__;. - The most up-to-date version of this document, along with - other documents for BIND 10, can be found at - . - - - - This is the messages manual for BIND 10 version - &__VERSION__;. - - - - Introduction - - This document lists each message that can be logged by the - programs in the BIND 10 package. Each entry in this manual - is of the form: - IDENTIFICATION message-text - ... where "IDENTIFICATION" is the message identification included - in each message logged and "message-text" is the accompanying - message text. The "message-text" may include placeholders of the - form "%1", "%2" etc.; these parameters are replaced by relevant - values when the message is logged. - - - Each entry is also accompanied by a description giving more - information about the circumstances that result in the message - being logged. - - - For information on configuring and using BIND 10 logging, - refer to the BIND 10 Guide. - - - - - BIND 10 Messages - - - - -ASIODNS_FD_ADD_TCP adding a new TCP server by opened fd %1 - -A debug message informing about installing a file descriptor as a server. -The file descriptor number is noted. - - - - -ASIODNS_FD_ADD_UDP adding a new UDP server by opened fd %1 - -A debug message informing about installing a file descriptor as a server. -The file descriptor number is noted. - - - - -ASIODNS_FETCH_COMPLETED upstream fetch to %1(%2) has now completed - -A debug message, this records that the upstream fetch (a query made by the -resolver on behalf of its client) to the specified address has completed. - - - - -ASIODNS_FETCH_STOPPED upstream fetch to %1(%2) has been stopped - -An external component has requested the halting of an upstream fetch. This -is an allowed operation, and the message should only appear if debug is -enabled. - - - - -ASIODNS_OPEN_SOCKET error %1 opening %2 socket to %3(%4) - -The asynchronous I/O code encountered an error when trying to open a socket -of the specified protocol in order to send a message to the target address. -The number of the system error that caused the problem is given in the -message. - - - - -ASIODNS_READ_DATA error %1 reading %2 data from %3(%4) - -The asynchronous I/O code encountered an error when trying to read data from -the specified address on the given protocol. The number of the system -error that caused the problem is given in the message. - - - - -ASIODNS_READ_TIMEOUT receive timeout while waiting for data from %1(%2) - -An upstream fetch from the specified address timed out. This may happen for -any number of reasons and is most probably a problem at the remote server -or a problem on the network. The message will only appear if debug is -enabled. - - - - -ASIODNS_SEND_DATA error %1 sending data using %2 to %3(%4) - -The asynchronous I/O code encountered an error when trying to send data to -the specified address on the given protocol. The number of the system -error that caused the problem is given in the message. - - - - -ASIODNS_UNKNOWN_ORIGIN unknown origin for ASIO error code %1 (protocol: %2, address %3) - -An internal consistency check on the origin of a message from the -asynchronous I/O module failed. This may indicate an internal error; -please submit a bug report. - - - - -ASIODNS_UNKNOWN_RESULT unknown result (%1) when IOFetch::stop() was executed for I/O to %2(%3) - -An internal error indicating that the termination method of the resolver's -upstream fetch class was called with an unknown result code (which is -given in the message). Please submit a bug report. - - - - -AUTH_AXFR_ERROR error handling AXFR request: %1 - -This is a debug message produced by the authoritative server when it -has encountered an error processing an AXFR request. The message gives -the reason for the error, and the server will return a SERVFAIL code to -the sender. - - - - -AUTH_AXFR_UDP AXFR query received over UDP - -This is a debug message output when the authoritative server has received -an AXFR query over UDP. Use of UDP for AXFRs is not permitted by the -protocol, so the server will return a FORMERR error to the sender. - - - - -AUTH_COMMAND_FAILED execution of command channel instruction '%1' failed: %2 - -Execution of the specified command by the authoritative server failed. The -message contains the reason for the failure. - - - - -AUTH_CONFIG_CHANNEL_CREATED configuration session channel created - -This is a debug message indicating that authoritative server has created -the channel to the configuration manager. It is issued during server -startup is an indication that the initialization is proceeding normally. - - - - -AUTH_CONFIG_CHANNEL_ESTABLISHED configuration session channel established - -This is a debug message indicating that authoritative server -has established communication the configuration manager over the -previously-created channel. It is issued during server startup is an -indication that the initialization is proceeding normally. - - - - -AUTH_CONFIG_CHANNEL_STARTED configuration session channel started - -This is a debug message, issued when the authoritative server has -posted a request to be notified when new configuration information is -available. It is issued during server startup is an indication that -the initialization is proceeding normally. - - - - -AUTH_CONFIG_LOAD_FAIL load of configuration failed: %1 - -An attempt to configure the server with information from the configuration -database during the startup sequence has failed. (The reason for -the failure is given in the message.) The server will continue its -initialization although it may not be configured in the desired way. - - - - -AUTH_CONFIG_UPDATE_FAIL update of configuration failed: %1 - -At attempt to update the configuration the server with information -from the configuration database has failed, the reason being given in -the message. - - - - -AUTH_DATA_SOURCE data source database file: %1 - -This is a debug message produced by the authoritative server when it accesses a -datebase data source, listing the file that is being accessed. - - - - -AUTH_DNS_SERVICES_CREATED DNS services created - -This is a debug message indicating that the component that will handling -incoming queries for the authoritative server (DNSServices) has been -successfully created. It is issued during server startup is an indication -that the initialization is proceeding normally. - - - - -AUTH_HEADER_PARSE_FAIL unable to parse header in received DNS packet: %1 - -This is a debug message, generated by the authoritative server when an -attempt to parse the header of a received DNS packet has failed. (The -reason for the failure is given in the message.) The server will drop the -packet. - - - - -AUTH_INVALID_STATISTICS_DATA invalid specification of statistics data specified - -An error was encountered when the authoritiative server specified -statistics data which is invalid for the auth specification file. - - - - -AUTH_LOAD_TSIG loading TSIG keys - -This is a debug message indicating that the authoritative server -has requested the keyring holding TSIG keys from the configuration -database. It is issued during server startup is an indication that the -initialization is proceeding normally. - - - - -AUTH_LOAD_ZONE loaded zone %1/%2 - -This debug message is issued during the processing of the 'loadzone' command -when the authoritative server has successfully loaded the named zone of the -named class. - - - - -AUTH_MEM_DATASRC_DISABLED memory data source is disabled for class %1 - -This is a debug message reporting that the authoritative server has -discovered that the memory data source is disabled for the given class. - - - - -AUTH_MEM_DATASRC_ENABLED memory data source is enabled for class %1 - -This is a debug message reporting that the authoritative server has -discovered that the memory data source is enabled for the given class. - - - - -AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY - -This debug message is logged by the authoritative server when it receives -a NOTIFY packet that contains zero or more than one question. (A valid -NOTIFY packet contains one question.) The server will return a FORMERR -error to the sender. - - - - -AUTH_NOTIFY_RRTYPE invalid question RR type (%1) in incoming NOTIFY - -This debug message is logged by the authoritative server when it receives -a NOTIFY packet that an RR type of something other than SOA in the -question section. (The RR type received is included in the message.) The -server will return a FORMERR error to the sender. - - - - -AUTH_NO_STATS_SESSION session interface for statistics is not available - -The authoritative server had no session with the statistics module at the -time it attempted to send it data: the attempt has been abandoned. This -could be an error in configuration. - - - - -AUTH_NO_XFRIN received NOTIFY but XFRIN session is not running - -This is a debug message produced by the authoritative server when it receives -a NOTIFY packet but the XFRIN process is not running. The packet will be -dropped and nothing returned to the sender. - - - - -AUTH_PACKET_PARSE_ERROR unable to parse received DNS packet: %1 - -This is a debug message, generated by the authoritative server when an -attempt to parse a received DNS packet has failed due to something other -than a protocol error. The reason for the failure is given in the message; -the server will return a SERVFAIL error code to the sender. - - - - -AUTH_PACKET_PROTOCOL_ERROR DNS packet protocol error: %1. Returning %2 - -This is a debug message, generated by the authoritative server when an -attempt to parse a received DNS packet has failed due to a protocol error. -The reason for the failure is given in the message, as is the error code -that will be returned to the sender. - - - - -AUTH_PACKET_RECEIVED message received:\n%1 - -This is a debug message output by the authoritative server when it -receives a valid DNS packet. - -Note: This message includes the packet received, rendered in the form of -multiple lines of text. For this reason, it is suggested that this log message -not be routed to the syslog file, where the multiple lines could confuse -programs that expect a format of one message per line. - - - - -AUTH_PROCESS_FAIL message processing failure: %1 - -This message is generated by the authoritative server when it has -encountered an internal error whilst processing a received packet: -the cause of the error is included in the message. - -The server will return a SERVFAIL error code to the sender of the packet. -This message indicates a potential error in the server. Please open a -bug ticket for this issue. - - - - -AUTH_RECEIVED_COMMAND command '%1' received - -This is a debug message issued when the authoritative server has received -a command on the command channel. - - - - -AUTH_RECEIVED_SENDSTATS command 'sendstats' received - -This is a debug message issued when the authoritative server has received -a command from the statistics module to send it data. The 'sendstats' -command is handled differently to other commands, which is why the debug -message associated with it has its own code. - - - - -AUTH_RESPONSE_RECEIVED received response message, ignoring - -This is a debug message, this is output if the authoritative server -receives a DNS packet with the QR bit set, i.e. a DNS response. The -server ignores the packet as it only responds to question packets. - - - - -AUTH_SEND_ERROR_RESPONSE sending an error response (%1 bytes):\n%2 - -This is a debug message recording that the authoritative server is sending -an error response to the originator of the query. A previous message will -have recorded details of the failure. - -Note: This message includes the packet sent, rendered in the form of -multiple lines of text. For this reason, it is suggested that this log message -not be routed to the syslog file, where the multiple lines could confuse -programs that expect a format of one message per line. - - - - -AUTH_SEND_NORMAL_RESPONSE sending an error response (%1 bytes):\n%2 - -This is a debug message recording that the authoritative server is sending -a response to the originator of a query. - -Note: This message includes the packet sent, rendered in the form of -multiple lines of text. For this reason, it is suggested that this log message -not be routed to the syslog file, where the multiple lines could confuse -programs that expect a format of one message per line. - - - - -AUTH_SERVER_CREATED server created - -An informational message indicating that the authoritative server process has -been created and is initializing. The AUTH_SERVER_STARTED message will be -output when initialization has successfully completed and the server starts -accepting queries. - - - - -AUTH_SERVER_FAILED server failed: %1 - -The authoritative server has encountered a fatal error and is terminating. The -reason for the failure is included in the message. - - - - -AUTH_SERVER_STARTED server started - -Initialization of the authoritative server has completed successfully -and it is entering the main loop, waiting for queries to arrive. - - - - -AUTH_SQLITE3 nothing to do for loading sqlite3 - -This is a debug message indicating that the authoritative server has -found that the data source it is loading is an SQLite3 data source, -so no further validation is needed. - - - - -AUTH_STATS_CHANNEL_CREATED STATS session channel created - -This is a debug message indicating that the authoritative server has -created a channel to the statistics process. It is issued during server -startup is an indication that the initialization is proceeding normally. - - - - -AUTH_STATS_CHANNEL_ESTABLISHED STATS session channel established - -This is a debug message indicating that the authoritative server -has established communication over the previously created statistics -channel. It is issued during server startup is an indication that the -initialization is proceeding normally. - - - - -AUTH_STATS_COMMS communication error in sending statistics data: %1 - -An error was encountered when the authoritative server tried to send data -to the statistics daemon. The message includes additional information -describing the reason for the failure. - - - - -AUTH_STATS_TIMEOUT timeout while sending statistics data: %1 - -The authoritative server sent data to the statistics daemon but received -no acknowledgement within the specified time. The message includes -additional information describing the reason for the failure. - - - - -AUTH_STATS_TIMER_DISABLED statistics timer has been disabled - -This is a debug message indicating that the statistics timer has been -disabled in the authoritative server and no statistics information is -being produced. - - - - -AUTH_STATS_TIMER_SET statistics timer set to %1 second(s) - -This is a debug message indicating that the statistics timer has been -enabled and that the authoritative server will produce statistics data -at the specified interval. - - - - -AUTH_UNSUPPORTED_OPCODE unsupported opcode: %1 - -This is a debug message, produced when a received DNS packet being -processed by the authoritative server has been found to contain an -unsupported opcode. (The opcode is included in the message.) The server -will return an error code of NOTIMPL to the sender. - - - - -AUTH_XFRIN_CHANNEL_CREATED XFRIN session channel created - -This is a debug message indicating that the authoritative server has -created a channel to the XFRIN (Transfer-in) process. It is issued -during server startup is an indication that the initialization is -proceeding normally. - - - - -AUTH_XFRIN_CHANNEL_ESTABLISHED XFRIN session channel established - -This is a debug message indicating that the authoritative server has -established communication over the previously-created channel to the -XFRIN (Transfer-in) process. It is issued during server startup is an -indication that the initialization is proceeding normally. - - - - -AUTH_ZONEMGR_COMMS error communicating with zone manager: %1 - -This is a debug message output during the processing of a NOTIFY request. -An error (listed in the message) has been encountered whilst communicating -with the zone manager. The NOTIFY request will not be honored. - - - - -AUTH_ZONEMGR_ERROR received error response from zone manager: %1 - -This is a debug message output during the processing of a NOTIFY -request. The zone manager component has been informed of the request, -but has returned an error response (which is included in the message). The -NOTIFY request will not be honored. - - - - -BIND10_CHECK_MSGQ_ALREADY_RUNNING checking if msgq is already running - -The boss process is starting up and will now check if the message bus -daemon is already running. If so, it will not be able to start, as it -needs a dedicated message bus. - - - - -BIND10_COMPONENT_FAILED component %1 (pid %2) failed with %3 exit status - -The process terminated, but the bind10 boss didn't expect it to, which means -it must have failed. - - - - -BIND10_COMPONENT_RESTART component %1 is about to restart - -The named component failed previously and we will try to restart it to provide -as flawless service as possible, but it should be investigated what happened, -as it could happen again. - - - - -BIND10_COMPONENT_START component %1 is starting - -The named component is about to be started by the boss process. - - - - -BIND10_COMPONENT_START_EXCEPTION component %1 failed to start: %2 - -An exception (mentioned in the message) happened during the startup of the -named component. The componet is not considered started and further actions -will be taken about it. - - - - -BIND10_COMPONENT_STOP component %1 is being stopped - -A component is about to be asked to stop willingly by the boss. - - - - -BIND10_COMPONENT_UNSATISFIED component %1 is required to run and failed - -A component failed for some reason (see previous messages). It is either a core -component or needed component that was just started. In any case, the system -can't continue without it and will terminate. - - - - -BIND10_CONFIGURATOR_BUILD building plan '%1' -> '%2' - -A debug message. This indicates that the configurator is building a plan -how to change configuration from the older one to newer one. This does no -real work yet, it just does the planning what needs to be done. - - - - -BIND10_CONFIGURATOR_PLAN_INTERRUPTED configurator plan interrupted, only %1 of %2 done - -There was an exception during some planned task. The plan will not continue and -only some tasks of the plan were completed. The rest is aborted. The exception -will be propagated. - - - - -BIND10_CONFIGURATOR_RECONFIGURE reconfiguring running components - -A different configuration of which components should be running is being -installed. All components that are no longer needed will be stopped and -newly introduced ones started. This happens at startup, when the configuration -is read the first time, or when an operator changes configuration of the boss. - - - - -BIND10_CONFIGURATOR_RUN running plan of %1 tasks - -A debug message. The configurator is about to execute a plan of actions it -computed previously. - - - - -BIND10_CONFIGURATOR_START bind10 component configurator is starting up - -The part that cares about starting and stopping the right component from the -boss process is starting up. This happens only once at the startup of the -boss process. It will start the basic set of processes now (the ones boss -needs to read the configuration), the rest will be started after the -configuration is known. - - - - -BIND10_CONFIGURATOR_STOP bind10 component configurator is shutting down - -The part that cares about starting and stopping processes in the boss is -shutting down. All started components will be shut down now (more precisely, -asked to terminate by their own, if they fail to comply, other parts of -the boss process will try to force them). - - - - -BIND10_CONFIGURATOR_TASK performing task %1 on %2 - -A debug message. The configurator is about to perform one task of the plan it -is currently executing on the named component. - - - - -BIND10_INVALID_STATISTICS_DATA invalid specification of statistics data specified - -An error was encountered when the boss module specified -statistics data which is invalid for the boss specification file. - - - - -BIND10_INVALID_USER invalid user: %1 - -The boss process was started with the -u option, to drop root privileges -and continue running as the specified user, but the user is unknown. - - - - -BIND10_KILLING_ALL_PROCESSES killing all started processes - -The boss module was not able to start every process it needed to start -during startup, and will now kill the processes that did get started. - - - - -BIND10_KILL_PROCESS killing process %1 - -The boss module is sending a kill signal to process with the given name, -as part of the process of killing all started processes during a failed -startup, as described for BIND10_KILLING_ALL_PROCESSES - - - - -BIND10_LOST_SOCKET_CONSUMER consumer %1 of sockets disconnected, considering all its sockets closed - -A connection from one of the applications which requested a socket was -closed. This means the application has terminated, so all the sockets it was -using are now closed and bind10 process can release them as well, unless the -same sockets are used by yet another application. - - - - -BIND10_MSGQ_ALREADY_RUNNING msgq daemon already running, cannot start - -There already appears to be a message bus daemon running. Either an -old process was not shut down correctly, and needs to be killed, or -another instance of BIND10, with the same msgq domain socket, is -running, which needs to be stopped. - - - - -BIND10_MSGQ_DISAPPEARED msgq channel disappeared - -While listening on the message bus channel for messages, it suddenly -disappeared. The msgq daemon may have died. This might lead to an -inconsistent state of the system, and BIND 10 will now shut down. - - - - -BIND10_NO_SOCKET couldn't send a socket for token %1 because of error: %2 - -An error occurred when the bind10 process was asked to send a socket file -descriptor. The error is mentioned, most common reason is that the request -is invalid and may not come from bind10 process at all. - - - - -BIND10_PROCESS_ENDED process %2 of %1 ended with status %3 - -This indicates a process started previously terminated. The process id -and component owning the process are indicated, as well as the exit code. -This doesn't distinguish if the process was supposed to terminate or not. - - - - -BIND10_READING_BOSS_CONFIGURATION reading boss configuration - -The boss process is starting up, and will now process the initial -configuration, as received from the configuration manager. - - - - -BIND10_RECEIVED_COMMAND received command: %1 - -The boss module received a command and shall now process it. The command -is printed. - - - - -BIND10_RECEIVED_NEW_CONFIGURATION received new configuration: %1 - -The boss module received a configuration update and is going to apply -it now. The new configuration is printed. - - - - -BIND10_RECEIVED_SIGNAL received signal %1 - -The boss module received the given signal. - - - - -BIND10_RESURRECTED_PROCESS resurrected %1 (PID %2) - -The given process has been restarted successfully, and is now running -with the given process id. - - - - -BIND10_RESURRECTING_PROCESS resurrecting dead %1 process... - -The given process has ended unexpectedly, and is now restarted. - - - - -BIND10_SELECT_ERROR error in select() call: %1 - -There was a fatal error in the call to select(), used to see if a child -process has ended or if there is a message on the message bus. This -should not happen under normal circumstances and is considered fatal, -so BIND 10 will now shut down. The specific error is printed. - - - - -BIND10_SEND_SIGKILL sending SIGKILL to %1 (PID %2) - -The boss module is sending a SIGKILL signal to the given process. - - - - -BIND10_SEND_SIGTERM sending SIGTERM to %1 (PID %2) - -The boss module is sending a SIGTERM signal to the given process. - - - - -BIND10_SETUID setting UID to %1 - -The boss switches the user it runs as to the given UID. - - - - -BIND10_SHUTDOWN stopping the server - -The boss process received a command or signal telling it to shut down. -It will send a shutdown command to each process. The processes that do -not shut down will then receive a SIGTERM signal. If that doesn't work, -it shall send SIGKILL signals to the processes still alive. - - - - -BIND10_SHUTDOWN_COMPLETE all processes ended, shutdown complete - -All child processes have been stopped, and the boss process will now -stop itself. - - - - -BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1 - -The socket creator reported an error when creating a socket. But the function -which failed is unknown (not one of 'S' for socket or 'B' for bind). - - - - -BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1 - -The boss requested a socket from the creator, but the answer is unknown. This -looks like a programmer error. - - - - -BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator - -There should be more data from the socket creator, but it closed the socket. -It probably crashed. - - - - -BIND10_SOCKCREATOR_INIT initializing socket creator parser - -The boss module initializes routines for parsing the socket creator -protocol. - - - - -BIND10_SOCKCREATOR_KILL killing the socket creator - -The socket creator is being terminated the aggressive way, by sending it -sigkill. This should not happen usually. - - - - -BIND10_SOCKCREATOR_TERMINATE terminating socket creator - -The boss module sends a request to terminate to the socket creator. - - - - -BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1 - -Either sending or receiving data from the socket creator failed with the given -error. The creator probably crashed or some serious OS-level problem happened, -as the communication happens only on local host. - - - - -BIND10_SOCKET_CREATED successfully created socket %1 - -The socket creator successfully created and sent a requested socket, it has -the given file number. - - - - -BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3 - -The socket creator failed to create the requested socket. It failed on the -indicated OS API function with given error. - - - - -BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator - -The boss forwards a request for a socket to the socket creator. - - - - -BIND10_STARTED_CC started configuration/command session - -Debug message given when BIND 10 has successfull started the object that -handles configuration and commands. - - - - -BIND10_STARTED_PROCESS started %1 - -The given process has successfully been started. - - - - -BIND10_STARTED_PROCESS_PID started %1 (PID %2) - -The given process has successfully been started, and has the given PID. - - - - -BIND10_STARTING starting BIND10: %1 - -Informational message on startup that shows the full version. - - - - -BIND10_STARTING_CC starting configuration/command session - -Informational message given when BIND 10 is starting the session object -that handles configuration and commands. - - - - -BIND10_STARTING_PROCESS starting process %1 - -The boss module is starting the given process. - - - - -BIND10_STARTING_PROCESS_PORT starting process %1 (to listen on port %2) - -The boss module is starting the given process, which will listen on the -given port number. - - - - -BIND10_STARTING_PROCESS_PORT_ADDRESS starting process %1 (to listen on %2#%3) - -The boss module is starting the given process, which will listen on the -given address and port number (written as <address>#<port>). - - - - -BIND10_STARTUP_COMPLETE BIND 10 started - -All modules have been successfully started, and BIND 10 is now running. - - - - -BIND10_STARTUP_ERROR error during startup: %1 - -There was a fatal error when BIND10 was trying to start. The error is -shown, and BIND10 will now shut down. - - - - -BIND10_STARTUP_UNEXPECTED_MESSAGE unrecognised startup message %1 - -During the startup process, a number of messages are exchanged between the -Boss process and the processes it starts. This error is output when a -message received by the Boss process is recognised as being of the -correct format but is unexpected. It may be that processes are starting -of sequence. - - - - -BIND10_STARTUP_UNRECOGNISED_MESSAGE unrecognised startup message %1 - -During the startup process, a number of messages are exchanged between the -Boss process and the processes it starts. This error is output when a -message received by the Boss process is not recognised. - - - - -BIND10_START_AS_NON_ROOT_AUTH starting b10-auth as a user, not root. This might fail. - -The authoritative server is being started or restarted without root privileges. -If the module needs these privileges, it may have problems starting. -Note that this issue should be resolved by the pending 'socket-creator' -process; once that has been implemented, modules should not need root -privileges anymore. See tickets #800 and #801 for more information. - - - - -BIND10_START_AS_NON_ROOT_RESOLVER starting b10-resolver as a user, not root. This might fail. - -The resolver is being started or restarted without root privileges. -If the module needs these privileges, it may have problems starting. -Note that this issue should be resolved by the pending 'socket-creator' -process; once that has been implemented, modules should not need root -privileges anymore. See tickets #800 and #801 for more information. - - - - -BIND10_STOP_PROCESS asking %1 to shut down - -The boss module is sending a shutdown command to the given module over -the message channel. - - - - -BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited - -An unknown child process has exited. The PID is printed, but no further -action will be taken by the boss process. - - - - -BIND10_WAIT_CFGMGR waiting for configuration manager process to initialize - -The configuration manager process is so critical to operation of BIND 10 -that after starting it, the Boss module will wait for it to initialize -itself before continuing. This debug message is produced during the -wait and may be output zero or more times depending on how long it takes -the configuration manager to start up. The total length of time Boss -will wait for the configuration manager before reporting an error is -set with the command line --wait switch, which has a default value of -ten seconds. - - - - -CACHE_ENTRY_MISSING_RRSET missing RRset to generate message for %1 - -The cache tried to generate the complete answer message. It knows the structure -of the message, but some of the RRsets to be put there are not in cache (they -probably expired already). Therefore it pretends the message was not found. - - - - -CACHE_LOCALZONE_FOUND found entry with key %1 in local zone data - -Debug message, noting that the requested data was successfully found in the -local zone data of the cache. - - - - -CACHE_LOCALZONE_UNKNOWN entry with key %1 not found in local zone data - -Debug message. The requested data was not found in the local zone data. - - - - -CACHE_LOCALZONE_UPDATE updating local zone element at key %1 - -Debug message issued when there's update to the local zone section of cache. - - - - -CACHE_MESSAGES_DEINIT deinitialized message cache - -Debug message. It is issued when the server deinitializes the message cache. - - - - -CACHE_MESSAGES_EXPIRED found an expired message entry for %1 in the message cache - -Debug message. The requested data was found in the message cache, but it -already expired. Therefore the cache removes the entry and pretends it found -nothing. - - - - -CACHE_MESSAGES_FOUND found a message entry for %1 in the message cache - -Debug message. We found the whole message in the cache, so it can be returned -to user without any other lookups. - - - - -CACHE_MESSAGES_INIT initialized message cache for %1 messages of class %2 - -Debug message issued when a new message cache is issued. It lists the class -of messages it can hold and the maximum size of the cache. - - - - -CACHE_MESSAGES_REMOVE removing old instance of %1/%2/%3 first - -Debug message. This may follow CACHE_MESSAGES_UPDATE and indicates that, while -updating, the old instance is being removed prior of inserting a new one. - - - - -CACHE_MESSAGES_UNCACHEABLE not inserting uncacheable message %1/%2/%3 - -Debug message, noting that the given message can not be cached. This is because -there's no SOA record in the message. See RFC 2308 section 5 for more -information. - - - - -CACHE_MESSAGES_UNKNOWN no entry for %1 found in the message cache - -Debug message. The message cache didn't find any entry for the given key. - - - - -CACHE_MESSAGES_UPDATE updating message entry %1/%2/%3 - -Debug message issued when the message cache is being updated with a new -message. Either the old instance is removed or, if none is found, new one -is created. - - - - -CACHE_RESOLVER_DEEPEST looking up deepest NS for %1/%2 - -Debug message. The resolver cache is looking up the deepest known nameserver, -so the resolution doesn't have to start from the root. - - - - -CACHE_RESOLVER_INIT initializing resolver cache for class %1 - -Debug message. The resolver cache is being created for this given class. - - - - -CACHE_RESOLVER_INIT_INFO initializing resolver cache for class %1 - -Debug message, the resolver cache is being created for this given class. The -difference from CACHE_RESOLVER_INIT is only in different format of passed -information, otherwise it does the same. - - - - -CACHE_RESOLVER_LOCAL_MSG message for %1/%2 found in local zone data - -Debug message. The resolver cache found a complete message for the user query -in the zone data. - - - - -CACHE_RESOLVER_LOCAL_RRSET RRset for %1/%2 found in local zone data - -Debug message. The resolver cache found a requested RRset in the local zone -data. - - - - -CACHE_RESOLVER_LOOKUP_MSG looking up message in resolver cache for %1/%2 - -Debug message. The resolver cache is trying to find a message to answer the -user query. - - - - -CACHE_RESOLVER_LOOKUP_RRSET looking up RRset in resolver cache for %1/%2 - -Debug message. The resolver cache is trying to find an RRset (which usually -originates as internally from resolver). - - - - -CACHE_RESOLVER_NO_QUESTION answer message for %1/%2 has empty question section - -The cache tried to fill in found data into the response message. But it -discovered the message contains no question section, which is invalid. -This is likely a programmer error, please submit a bug report. - - - - -CACHE_RESOLVER_UNKNOWN_CLASS_MSG no cache for class %1 - -Debug message. While trying to lookup a message in the resolver cache, it was -discovered there's no cache for this class at all. Therefore no message is -found. - - - - -CACHE_RESOLVER_UNKNOWN_CLASS_RRSET no cache for class %1 - -Debug message. While trying to lookup an RRset in the resolver cache, it was -discovered there's no cache for this class at all. Therefore no data is found. - - - - -CACHE_RESOLVER_UPDATE_MSG updating message for %1/%2/%3 - -Debug message. The resolver is updating a message in the cache. - - - - -CACHE_RESOLVER_UPDATE_RRSET updating RRset for %1/%2/%3 - -Debug message. The resolver is updating an RRset in the cache. - - - - -CACHE_RESOLVER_UPDATE_UNKNOWN_CLASS_MSG no cache for class %1 - -Debug message. While trying to insert a message into the cache, it was -discovered that there's no cache for the class of message. Therefore -the message will not be cached. - - - - -CACHE_RESOLVER_UPDATE_UNKNOWN_CLASS_RRSET no cache for class %1 - -Debug message. While trying to insert an RRset into the cache, it was -discovered that there's no cache for the class of the RRset. Therefore -the message will not be cached. - - - - -CACHE_RRSET_EXPIRED found expired RRset %1/%2/%3 - -Debug message. The requested data was found in the RRset cache. However, it is -expired, so the cache removed it and is going to pretend nothing was found. - - - - -CACHE_RRSET_INIT initializing RRset cache for %1 RRsets of class %2 - -Debug message. The RRset cache to hold at most this many RRsets for the given -class is being created. - - - - -CACHE_RRSET_LOOKUP looking up %1/%2/%3 in RRset cache - -Debug message. The resolver is trying to look up data in the RRset cache. - - - - -CACHE_RRSET_NOT_FOUND no RRset found for %1/%2/%3 in cache - -Debug message which can follow CACHE_RRSET_LOOKUP. This means the data is not -in the cache. - - - - -CACHE_RRSET_REMOVE_OLD removing old RRset for %1/%2/%3 to make space for new one - -Debug message which can follow CACHE_RRSET_UPDATE. During the update, the cache -removed an old instance of the RRset to replace it with the new one. - - - - -CACHE_RRSET_UNTRUSTED not replacing old RRset for %1/%2/%3, it has higher trust level - -Debug message which can follow CACHE_RRSET_UPDATE. The cache already holds the -same RRset, but from more trusted source, so the old one is kept and new one -ignored. - - - - -CACHE_RRSET_UPDATE updating RRset %1/%2/%3 in the cache - -Debug message. The RRset is updating its data with this given RRset. - - - - -CC_ASYNC_READ_FAILED asynchronous read failed - -This marks a low level error, we tried to read data from the message queue -daemon asynchronously, but the ASIO library returned an error. - - - - -CC_CONN_ERROR error connecting to message queue (%1) - -It is impossible to reach the message queue daemon for the reason given. It -is unlikely there'll be reason for whatever program this currently is to -continue running, as the communication with the rest of BIND 10 is vital -for the components. - - - - -CC_DISCONNECT disconnecting from message queue daemon - -The library is disconnecting from the message queue daemon. This debug message -indicates that the program is trying to shut down gracefully. - - - - -CC_ESTABLISH trying to establish connection with message queue daemon at %1 - -This debug message indicates that the command channel library is about to -connect to the message queue daemon, which should be listening on the UNIX-domain -socket listed in the output. - - - - -CC_ESTABLISHED successfully connected to message queue daemon - -This debug message indicates that the connection was successfully made, this -should follow CC_ESTABLISH. - - - - -CC_GROUP_RECEIVE trying to receive a message - -Debug message, noting that a message is expected to come over the command -channel. - - - - -CC_GROUP_RECEIVED message arrived ('%1', '%2') - -Debug message, noting that we successfully received a message (its envelope and -payload listed). This follows CC_GROUP_RECEIVE, but might happen some time -later, depending if we waited for it or just polled. - - - - -CC_GROUP_SEND sending message '%1' to group '%2' - -Debug message, we're about to send a message over the command channel. - - - - -CC_INVALID_LENGTHS invalid length parameters (%1, %2) - -This happens when garbage comes over the command channel or some kind of -confusion happens in the program. The data received from the socket make no -sense if we interpret it as lengths of message. The first one is total length -of the message; the second is the length of the header. The header -and its length (2 bytes) is counted in the total length. - - - - -CC_LENGTH_NOT_READY length not ready - -There should be data representing the length of message on the socket, but it -is not there. - - - - -CC_NO_MESSAGE no message ready to be received yet - -The program polled for incoming messages, but there was no message waiting. -This is a debug message which may happen only after CC_GROUP_RECEIVE. - - - - -CC_NO_MSGQ unable to connect to message queue (%1) - -It isn't possible to connect to the message queue daemon, for reason listed. -It is unlikely any program will be able continue without the communication. - - - - -CC_READ_ERROR error reading data from command channel (%1) - -A low level error happened when the library tried to read data from the -command channel socket. The reason is listed. - - - - -CC_READ_EXCEPTION error reading data from command channel (%1) - -We received an exception while trying to read data from the command -channel socket. The reason is listed. - - - - -CC_REPLY replying to message from '%1' with '%2' - -Debug message, noting we're sending a response to the original message -with the given envelope. - - - - -CC_SET_TIMEOUT setting timeout to %1ms - -Debug message. A timeout for which the program is willing to wait for a reply -is being set. - - - - -CC_START_READ starting asynchronous read - -Debug message. From now on, when a message (or command) comes, it'll wake the -program and the library will automatically pass it over to correct place. - - - - -CC_SUBSCRIBE subscribing to communication group %1 - -Debug message. The program wants to receive messages addressed to this group. - - - - -CC_TIMEOUT timeout reading data from command channel - -The program waited too long for data from the command channel (usually when it -sent a query to different program and it didn't answer for whatever reason). - - - - -CC_UNSUBSCRIBE unsubscribing from communication group %1 - -Debug message. The program no longer wants to receive messages addressed to -this group. - - - - -CC_WRITE_ERROR error writing data to command channel (%1) - -A low level error happened when the library tried to write data to the command -channel socket. - - - - -CC_ZERO_LENGTH invalid message length (0) - -The library received a message length being zero, which makes no sense, since -all messages must contain at least the envelope. - - - - -CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE Updating configuration database from version %1 to %2 - -An older version of the configuration database has been found, from which -there was an automatic upgrade path to the current version. These changes -are now applied, and no action from the administrator is necessary. - - - - -CFGMGR_BAD_UPDATE_RESPONSE_FROM_MODULE Unable to parse response from module %1: %2 - -The configuration manager sent a configuration update to a module, but -the module responded with an answer that could not be parsed. The answer -message appears to be invalid JSON data, or not decodable to a string. -This is likely to be a problem in the module in question. The update is -assumed to have failed, and will not be stored. - - - - -CFGMGR_CC_SESSION_ERROR Error connecting to command channel: %1 - -The configuration manager daemon was unable to connect to the messaging -system. The most likely cause is that msgq is not running. - - - - -CFGMGR_DATA_READ_ERROR error reading configuration database from disk: %1 - -There was a problem reading the persistent configuration data as stored -on disk. The file may be corrupted, or it is of a version from where -there is no automatic upgrade path. The file needs to be repaired or -removed. The configuration manager daemon will now shut down. - - - - -CFGMGR_IOERROR_WHILE_WRITING_CONFIGURATION Unable to write configuration file; configuration not stored: %1 - -There was an IO error from the system while the configuration manager -was trying to write the configuration database to disk. The specific -error is given. The most likely cause is that the directory where -the file is stored does not exist, or is not writable. The updated -configuration is not stored. - - - - -CFGMGR_OSERROR_WHILE_WRITING_CONFIGURATION Unable to write configuration file; configuration not stored: %1 - -There was an OS error from the system while the configuration manager -was trying to write the configuration database to disk. The specific -error is given. The most likely cause is that the system does not have -write access to the configuration database file. The updated -configuration is not stored. - - - - -CFGMGR_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the cfgmgr daemon. The -daemon will now shut down. - - - - -CMDCTL_BAD_CONFIG_DATA error in config data: %1 - -There was an error reading the updated configuration data. The specific -error is printed. - - - - -CMDCTL_BAD_PASSWORD bad password for user: %1 - -A login attempt was made to b10-cmdctl, but the password was wrong. -Users can be managed with the tool b10-cmdctl-usermgr. - - - - -CMDCTL_CC_SESSION_ERROR error reading from cc channel: %1 - -There was a problem reading from the command and control channel. The -most likely cause is that the message bus daemon is not running. - - - - -CMDCTL_CC_SESSION_TIMEOUT timeout on cc channel - -A timeout occurred when waiting for essential data from the cc session. -This usually occurs when b10-cfgmgr is not running or not responding. -Since we are waiting for essential information, this is a fatal error, -and the cmdctl daemon will now shut down. - - - - -CMDCTL_COMMAND_ERROR error in command %1 to module %2: %3 - -An error was encountered sending the given command to the given module. -Either there was a communication problem with the module, or the module -was not able to process the command, and sent back an error. The -specific error is printed in the message. - - - - -CMDCTL_COMMAND_SENT command '%1' to module '%2' was sent - -This debug message indicates that the given command has been sent to -the given module. - - - - -CMDCTL_NO_SUCH_USER username not found in user database: %1 - -A login attempt was made to b10-cmdctl, but the username was not known. -Users can be added with the tool b10-cmdctl-usermgr. - - - - -CMDCTL_NO_USER_ENTRIES_READ failed to read user information, all users will be denied - -The b10-cmdctl daemon was unable to find any user data in the user -database file. Either it was unable to read the file (in which case -this message follows a message CMDCTL_USER_DATABASE_READ_ERROR -containing a specific error), or the file was empty. Users can be added -with the tool b10-cmdctl-usermgr. - - - - -CMDCTL_SEND_COMMAND sending command %1 to module %2 - -This debug message indicates that the given command is being sent to -the given module. - - - - -CMDCTL_SSL_SETUP_FAILURE_USER_DENIED failed to create an SSL connection (user denied): %1 - -The user was denied because the SSL connection could not successfully -be set up. The specific error is given in the log message. Possible -causes may be that the ssl request itself was bad, or the local key or -certificate file could not be read. - - - - -CMDCTL_STARTED cmdctl is listening for connections on %1:%2 - -The cmdctl daemon has started and is now listening for connections. - - - - -CMDCTL_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the cmdctl daemon. The -daemon will now shut down. - - - - -CMDCTL_UNCAUGHT_EXCEPTION uncaught exception: %1 - -The b10-cmdctl daemon encountered an uncaught exception and -will now shut down. This is indicative of a programming error and -should not happen under normal circumstances. The exception message -is printed. - - - - -CMDCTL_USER_DATABASE_READ_ERROR failed to read user database file %1: %2 - -The b10-cmdctl daemon was unable to read the user database file. The -file may be unreadable for the daemon, or it may be corrupted. In the -latter case, it can be recreated with b10-cmdctl-usermgr. The specific -error is printed in the log message. - - - - -CONFIG_CCSESSION_MSG error in CC session message: %1 - -There was a problem with an incoming message on the command and control -channel. The message does not appear to be a valid command, and is -missing a required element or contains an unknown data format. This -most likely means that another BIND10 module is sending a bad message. -The message itself is ignored by this module. - - - - -CONFIG_CCSESSION_MSG_INTERNAL error handling CC session message: %1 - -There was an internal problem handling an incoming message on the command -and control channel. An unexpected exception was thrown, details of -which are appended to the message. The module will continue to run, -but will not send back an answer. - -The most likely cause of this error is a programming error. Please raise -a bug report. - - - - -CONFIG_GET_FAIL error getting configuration from cfgmgr: %1 - -The configuration manager returned an error when this module requested -the configuration. The full error message answer from the configuration -manager is appended to the log error. The most likely cause is that -the module is of a different (command specification) version than the -running configuration manager. - - - - -CONFIG_GET_FAILED error getting configuration from cfgmgr: %1 - -The configuration manager returned an error response when the module -requested its configuration. The full error message answer from the -configuration manager is appended to the log error. - - - - -CONFIG_JSON_PARSE JSON parse error in %1: %2 - -There was an error parsing the JSON file. The given file does not appear -to be in valid JSON format. Please verify that the filename is correct -and that the contents are valid JSON. - - - - -CONFIG_LOG_CONFIG_ERRORS error(s) in logging configuration: %1 - -There was a logging configuration update, but the internal validator -for logging configuration found that it contained errors. The errors -are shown, and the update is ignored. - - - - -CONFIG_LOG_EXPLICIT will use logging configuration for explicitly-named logger %1 - -This is a debug message. When processing the "loggers" part of the -configuration file, the configuration library found an entry for the named -logger that matches the logger specification for the program. The logging -configuration for the program will be updated with the information. - - - - -CONFIG_LOG_IGNORE_EXPLICIT ignoring logging configuration for explicitly-named logger %1 - -This is a debug message. When processing the "loggers" part of the -configuration file, the configuration library found an entry for the -named logger. As this does not match the logger specification for the -program, it has been ignored. - - - - -CONFIG_LOG_IGNORE_WILD ignoring logging configuration for wildcard logger %1 - -This is a debug message. When processing the "loggers" part of the -configuration file, the configuration library found the named wildcard -entry (one containing the "*" character) that matched a logger already -matched by an explicitly named entry. The configuration is ignored. - - - - -CONFIG_LOG_WILD_MATCH will use logging configuration for wildcard logger %1 - -This is a debug message. When processing the "loggers" part of -the configuration file, the configuration library found the named -wildcard entry (one containing the "*" character) that matches a logger -specification in the program. The logging configuration for the program -will be updated with the information. - - - - -CONFIG_MOD_SPEC_FORMAT module specification error in %1: %2 - -The given file does not appear to be a valid specification file: details -are included in the message. Please verify that the filename is correct -and that its contents are a valid BIND10 module specification. - - - - -CONFIG_MOD_SPEC_REJECT module specification rejected by cfgmgr: %1 - -The specification file for this module was rejected by the configuration -manager. The full error message answer from the configuration manager is -appended to the log error. The most likely cause is that the module is of -a different (specification file) version than the running configuration -manager. - - - - -CONFIG_OPEN_FAIL error opening %1: %2 - -There was an error opening the given file. The reason for the failure -is included in the message. - - - - -DATASRC_CACHE_CREATE creating the hotspot cache - -This is a debug message issued during startup when the hotspot cache -is created. - - - - -DATASRC_CACHE_DESTROY destroying the hotspot cache - -Debug information. The hotspot cache is being destroyed. - - - - -DATASRC_CACHE_DISABLE disabling the hotspot cache - -A debug message issued when the hotspot cache is disabled. - - - - -DATASRC_CACHE_ENABLE enabling the hotspot cache - -A debug message issued when the hotspot cache is enabled. - - - - -DATASRC_CACHE_EXPIRED item '%1' in the hotspot cache has expired - -A debug message issued when a hotspot cache lookup located the item but it -had expired. The item was removed and the program proceeded as if the item -had not been found. - - - - -DATASRC_CACHE_FOUND the item '%1' was found - -Debug information. An item was successfully located in the hotspot cache. - - - - -DATASRC_CACHE_FULL hotspot cache is full, dropping oldest - -Debug information. After inserting an item into the hotspot cache, the -maximum number of items was exceeded, so the least recently used item will -be dropped. This should be directly followed by CACHE_REMOVE. - - - - -DATASRC_CACHE_INSERT inserting item '%1' into the hotspot cache - -A debug message indicating that a new item is being inserted into the hotspot -cache. - - - - -DATASRC_CACHE_NOT_FOUND the item '%1' was not found in the hotspot cache - -A debug message issued when hotspot cache was searched for the specified -item but it was not found. - - - - -DATASRC_CACHE_OLD_FOUND older instance of hotspot cache item '%1' found, replacing - -Debug information. While inserting an item into the hotspot cache, an older -instance of an item with the same name was found; the old instance will be -removed. This will be directly followed by CACHE_REMOVE. - - - - -DATASRC_CACHE_REMOVE removing '%1' from the hotspot cache - -Debug information. An item is being removed from the hotspot cache. - - - - -DATASRC_CACHE_SLOTS setting the hotspot cache size to '%1', dropping '%2' items - -The maximum allowed number of items of the hotspot cache is set to the given -number. If there are too many, some of them will be dropped. The size of 0 -means no limit. - - - - -DATASRC_DATABASE_COVER_NSEC_UNSUPPORTED %1 doesn't support DNSSEC when asked for NSEC data covering %2 - -The datasource tried to provide an NSEC proof that the named domain does not -exist, but the database backend doesn't support DNSSEC. No proof is included -in the answer as a result. - - - - -DATASRC_DATABASE_FIND_RECORDS looking in datasource %1 for record %2/%3/%4 - -Debug information. The database data source is looking up records with the given -name and type in the database. - - - - -DATASRC_DATABASE_FIND_TTL_MISMATCH TTL values differ in %1 for elements of %2/%3/%4, setting to %5 - -The datasource backend provided resource records for the given RRset with -different TTL values. This isn't allowed on the wire and is considered -an error, so we set it to the lowest value we found (but we don't modify the -database). The data in database should be checked and fixed. - - - - -DATASRC_DATABASE_FOUND_ANY search in datasource %1 resulted in returning all records of %2 - -The data returned by the database backend contained data for the given domain -name, so all the RRsets of the domain are returned. - - - - -DATASRC_DATABASE_FOUND_CNAME search in datasource %1 for %2/%3/%4 found CNAME, resulting in %5 - -When searching the domain for a name a CNAME was found at that name. -Even though it was not the RR type being sought, it is returned. (The -caller may want to continue the lookup by replacing the query name with -the canonical name and restarting the query with the original RR type.) - - - - -DATASRC_DATABASE_FOUND_DELEGATION Found delegation at %2 in %1 - -When searching for a domain, the program met a delegation to a different zone -at the given domain name. It will return that one instead. - - - - -DATASRC_DATABASE_FOUND_DELEGATION_EXACT search in datasource %1 for %2/%3/%4 found delegation at %5 - -The program found the domain requested, but it is a delegation point to a -different zone, therefore it is not authoritative for this domain name. -It will return the NS record instead. - - - - -DATASRC_DATABASE_FOUND_DNAME Found DNAME at %2 in %1 - -When searching for a domain, the program met a DNAME redirection to a different -place in the domain space at the given domain name. It will return that one -instead. - - - - -DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL empty non-terminal %2 in %1 - -The domain name does not have any RRs associated with it, so it doesn't -exist in the database. However, it has a subdomain, so it does exist -in the DNS address space. This type of domain is known an an "empty -non-terminal" and so we return NXRRSET instead of NXDOMAIN. - - - - -DATASRC_DATABASE_FOUND_NXDOMAIN search in datasource %1 resulted in NXDOMAIN for %2/%3/%4 - -The data returned by the database backend did not contain any data for the given -domain name, class and type. - - - - -DATASRC_DATABASE_FOUND_NXRRSET search in datasource %1 for %2/%3/%4 resulted in NXRRSET - -The data returned by the database backend contained data for the given domain -name and class, but not for the given type. - - - - -DATASRC_DATABASE_FOUND_NXRRSET_NSEC search in datasource %1 for %2/%3/%4 resulted in RRset %5 - -A search in the database for RRs for the specified name, type and class has -located RRs that match the name and class but not the type. DNSSEC information -has been requested and returned. - - - - -DATASRC_DATABASE_FOUND_RRSET search in datasource %1 resulted in RRset %5 - -The data returned by the database backend contained data for the given domain -name, and it either matches the type or has a relevant type. The RRset that is -returned is printed. - - - - -DATASRC_DATABASE_ITERATE iterating zone %1 - -The program is reading the whole zone, eg. not searching for data, but going -through each of the RRsets there. - - - - -DATASRC_DATABASE_ITERATE_END iterating zone finished - -While iterating through the zone, the program reached end of the data. - - - - -DATASRC_DATABASE_ITERATE_NEXT next RRset in zone is %1/%2 - -While iterating through the zone, the program extracted next RRset from it. -The name and RRtype of the RRset is indicated in the message. - - - - -DATASRC_DATABASE_ITERATE_TTL_MISMATCH TTL values differ for RRs of %1/%2/%3, setting to %4 - -While iterating through the zone, the time to live for RRs of the given RRset -were found to be different. This isn't allowed on the wire and is considered -an error, so we set it to the lowest value we found (but we don't modify the -database). The data in database should be checked and fixed. - - - - -DATASRC_DATABASE_JOURNALREADER_END %1/%2 on %3 from %4 to %5 - -This is a debug message indicating that the program (successfully) -reaches the end of sequences of a zone's differences. The zone's name -and class, database name, and the start and end serials are shown in -the message. - - - - -DATASRC_DATABASE_JOURNALREADER_NEXT %1/%2 in %3/%4 on %5 - -This is a debug message indicating that the program retrieves one -difference in difference sequences of a zone and successfully converts -it to an RRset. The zone's name and class, database name, and the -name and RR type of the retrieved diff are shown in the message. - - - - -DATASRC_DATABASE_JOURNALREADER_START %1/%2 on %3 from %4 to %5 - -This is a debug message indicating that the program starts reading -a zone's difference sequences from a database-based data source. The -zone's name and class, database name, and the start and end serials -are shown in the message. - - - - -DATASRC_DATABASE_JOURNALREADR_BADDATA failed to convert a diff to RRset in %1/%2 on %3 between %4 and %5: %6 - -This is an error message indicating that a zone's diff is broken and -the data source library failed to convert it to a valid RRset. The -most likely cause of this is that someone has manually modified the -zone's diff in the database and inserted invalid data as a result. -The zone's name and class, database name, and the start and end -serials, and an additional detail of the error are shown in the -message. The administrator should examine the diff in the database -to find any invalid data and fix it. - - - - -DATASRC_DATABASE_NO_MATCH not match for %2/%3/%4 in %1 - -No match (not even a wildcard) was found in the named data source for the given -name/type/class in the data source. - - - - -DATASRC_DATABASE_UPDATER_COMMIT updates committed for '%1/%2' on %3 - -Debug information. A set of updates to a zone has been successfully -committed to the corresponding database backend. The zone name, -its class and the database name are printed. - - - - -DATASRC_DATABASE_UPDATER_COMMIT (1) updates committed for '%1/%2' on %3 - -Debug information. A set of updates to a zone has been successfully -committed to the corresponding database backend. The zone name, -its class and the database name are printed. - - - - -DATASRC_DATABASE_UPDATER_CREATED zone updater created for '%1/%2' on %3 - -Debug information. A zone updater object is created to make updates to -the shown zone on the shown backend database. - - - - -DATASRC_DATABASE_UPDATER_CREATED (1) zone updater created for '%1/%2' on %3 - -Debug information. A zone updater object is created to make updates to -the shown zone on the shown backend database. - - - - -DATASRC_DATABASE_UPDATER_DESTROYED zone updater destroyed for '%1/%2' on %3 - -Debug information. A zone updater object is destroyed, either successfully -or after failure of, making updates to the shown zone on the shown backend -database. - - - - -DATASRC_DATABASE_UPDATER_DESTROYED (1) zone updater destroyed for '%1/%2' on %3 - -Debug information. A zone updater object is destroyed, either successfully -or after failure of, making updates to the shown zone on the shown backend -database. - - - - -DATASRC_DATABASE_UPDATER_ROLLBACK zone updates roll-backed for '%1/%2' on %3 - -A zone updater is being destroyed without committing the changes. -This would typically mean the update attempt was aborted due to some -error, but may also be a bug of the application that forgets committing -the changes. The intermediate changes made through the updater won't -be applied to the underlying database. The zone name, its class, and -the underlying database name are shown in the log message. - - - - -DATASRC_DATABASE_UPDATER_ROLLBACK (1) zone updates roll-backed for '%1/%2' on %3 - -A zone updater is being destroyed without committing the changes. -This would typically mean the update attempt was aborted due to some -error, but may also be a bug of the application that forgets committing -the changes. The intermediate changes made through the updater won't -be applied to the underlying database. The zone name, its class, and -the underlying database name are shown in the log message. - - - - -DATASRC_DATABASE_UPDATER_ROLLBACKFAIL failed to roll back zone updates for '%1/%2' on %3: %4 - -A zone updater is being destroyed without committing the changes to -the database, and attempts to rollback incomplete updates, but it -unexpectedly fails. The higher level implementation does not expect -it to fail, so this means either a serious operational error in the -underlying data source (such as a system failure of a database) or -software bug in the underlying data source implementation. In either -case if this message is logged the administrator should carefully -examine the underlying data source to see what exactly happens and -whether the data is still valid. The zone name, its class, and the -underlying database name as well as the error message thrown from the -database module are shown in the log message. - - - - -DATASRC_DATABASE_UPDATER_ROLLBACKFAIL (1) failed to roll back zone updates for '%1/%2' on %3: %4 - -A zone updater is being destroyed without committing the changes to -the database, and attempts to rollback incomplete updates, but it -unexpectedly fails. The higher level implementation does not expect -it to fail, so this means either a serious operational error in the -underlying data source (such as a system failure of a database) or -software bug in the underlying data source implementation. In either -case if this message is logged the administrator should carefully -examine the underlying data source to see what exactly happens and -whether the data is still valid. The zone name, its class, and the -underlying database name as well as the error message thrown from the -database module are shown in the log message. - - - - -DATASRC_DATABASE_WILDCARD_ANY search in datasource %1 resulted in wildcard match type ANY on %2 - -The database doesn't contain directly matching name. When searching -for a wildcard match, a wildcard record matching the name of the query -containing some RRsets was found. All the RRsets of the node are returned. - - - - -DATASRC_DATABASE_WILDCARD_CANCEL_NS canceled wildcard match on %3 because %2 contains NS (data source %1) - -The database was queried to provide glue data and it didn't find direct match. -It could create it from given wildcard, but matching wildcards is forbidden -under a zone cut, which was found. Therefore the delegation will be returned -instead. - - - - -DATASRC_DATABASE_WILDCARD_CANCEL_SUB wildcard %2 can't be used to construct %3 because %4 exists in %1 - -The answer could be constructed using the wildcard, but the given subdomain -exists, therefore this name is something like empty non-terminal (actually, -from the protocol point of view, it is empty non-terminal, but the code -discovers it differently). - - - - -DATASRC_DATABASE_WILDCARD_CNAME search in datasource %1 for %2/%3/%4 found wildcard CNAME at %5, resulting in %6 - -The database doesn't contain directly matching name. When searching -for a wildcard match, a CNAME RR was found at a wildcard record -matching the name. This is returned as the result of the search. - - - - -DATASRC_DATABASE_WILDCARD_EMPTY found subdomains of %2 which is a wildcard match for %3 in %1 - -The given wildcard matches the name being sough but it as an empty -nonterminal (e.g. there's nothing at *.example.com but something like -subdomain.*.example.org, do exist: so *.example.org exists in the -namespace but has no RRs assopciated with it). This will produce NXRRSET. - - - - -DATASRC_DATABASE_WILDCARD_MATCH search in datasource %1 resulted in wildcard match at %5 with RRset %6 - -The database doesn't contain directly matching name. When searching -for a wildcard match, a wildcard record matching the name and type of -the query was found. The data at this point is returned. - - - - -DATASRC_DATABASE_WILDCARD_NS search in datasource %1 for %2/%3/%4 found wildcard delegation at %5, resulting in %6 - -The database doesn't contain directly matching name. When searching -for a wildcard match, an NS RR was found at a wildcard record matching -the name. This is returned as the result of the search. - - - - -DATASRC_DATABASE_WILDCARD_NXRRSET search in datasource %1 for %2/%3/%4 resulted in wildcard NXRRSET at %5 - -The database doesn't contain directly matching name. When searching -for a wildcard match, a matching wildcard entry was found but it did -not contain RRs the requested type. AN NXRRSET indication is returned. - - - - -DATASRC_DO_QUERY handling query for '%1/%2' - -A debug message indicating that a query for the given name and RR type is being -processed. - - - - -DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3' - -Debug information. An RRset is being added to the in-memory data source. - - - - -DATASRC_MEM_ADD_WILDCARD adding wildcards for '%1' - -This is a debug message issued during the processing of a wildcard -name. The internal domain name tree is scanned and some nodes are -specially marked to allow the wildcard lookup to succeed. - - - - -DATASRC_MEM_ADD_ZONE adding zone '%1/%2' - -Debug information. A zone is being added into the in-memory data source. - - - - -DATASRC_MEM_ANY_SUCCESS ANY query for '%1' successful - -Debug information. The domain was found and an ANY type query is being answered -by providing everything found inside the domain. - - - - -DATASRC_MEM_CNAME CNAME at the domain '%1' - -Debug information. The requested domain is an alias to a different domain, -returning the CNAME instead. - - - - -DATASRC_MEM_CNAME_COEXIST can't add data to CNAME in domain '%1' - -This is the same problem as in MEM_CNAME_TO_NONEMPTY, but it happened the -other way around -- adding some other data to CNAME. - - - - -DATASRC_MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1' - -Someone or something tried to add a CNAME into a domain that already contains -some other data. But the protocol forbids coexistence of CNAME with anything -(RFC 1034, section 3.6.2). This indicates a problem with provided data. - - - - -DATASRC_MEM_CREATE creating zone '%1' in '%2' class - -Debug information. A representation of a zone for the in-memory data source is -being created. - - - - -DATASRC_MEM_DELEG_FOUND delegation found at '%1' - -Debug information. A delegation point was found above the requested record. - - - - -DATASRC_MEM_DESTROY destroying zone '%1' in '%2' class - -Debug information. A zone from in-memory data source is being destroyed. - - - - -DATASRC_MEM_DNAME_ENCOUNTERED encountered a DNAME - -Debug information. While searching for the requested domain, a DNAME was -encountered on the way. This may lead to redirection to a different domain and -stop the search. - - - - -DATASRC_MEM_DNAME_FOUND DNAME found at '%1' - -Debug information. A DNAME was found instead of the requested information. - - - - -DATASRC_MEM_DNAME_NS DNAME and NS can't coexist in non-apex domain '%1' - -A request was made for DNAME and NS records to be put into the same -domain which is not the apex (the top of the zone). This is forbidden -by RFC 2672 (section 3) and indicates a problem with provided data. - - - - -DATASRC_MEM_DOMAIN_EMPTY requested domain '%1' is empty - -Debug information. The requested domain exists in the tree of domains, but -it is empty. Therefore it doesn't contain the requested resource type. - - - - -DATASRC_MEM_DUP_RRSET duplicate RRset '%1/%2' - -An RRset is being inserted into in-memory data source for a second time. The -original version must be removed first. Note that loading master files where an -RRset is split into multiple locations is not supported yet. - - - - -DATASRC_MEM_EXACT_DELEGATION delegation at the exact domain '%1' - -Debug information. There's a NS record at the requested domain. This means -this zone is not authoritative for the requested domain, but a delegation -should be followed. The requested domain is an apex of some zone. - - - - -DATASRC_MEM_FIND find '%1/%2' - -Debug information. A search for the requested RRset is being started. - - - - -DATASRC_MEM_FIND_ZONE looking for zone '%1' - -Debug information. A zone object for this zone is being searched for in the -in-memory data source. - - - - -DATASRC_MEM_LOAD loading zone '%1' from file '%2' - -Debug information. The content of master file is being loaded into the memory. - - - - -DATASRC_MEM_NOT_FOUND requested domain '%1' not found - -Debug information. The requested domain does not exist. - - - - -DATASRC_MEM_NS_ENCOUNTERED encountered a NS - -Debug information. While searching for the requested domain, a NS was -encountered on the way (a delegation). This may lead to stop of the search. - - - - -DATASRC_MEM_NXRRSET no such type '%1' at '%2' - -Debug information. The domain exists, but it doesn't hold any record of the -requested type. - - - - -DATASRC_MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2' - -It was attempted to add the domain into a zone that shouldn't have it -(eg. the domain is not subdomain of the zone origin). This indicates a -problem with provided data. - - - - -DATASRC_MEM_RENAME renaming RRset from '%1' to '%2' - -Debug information. A RRset is being generated from a different RRset (most -probably a wildcard). So it must be renamed to whatever the user asked for. In -fact, it's impossible to rename RRsets with our libraries, so a new one is -created and all resource records are copied over. - - - - -DATASRC_MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2' - -Some resource types are singletons -- only one is allowed in a domain -(for example CNAME or SOA). This indicates a problem with provided data. - - - - -DATASRC_MEM_SUCCESS query for '%1/%2' successful - -Debug information. The requested record was found. - - - - -DATASRC_MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty - -Debug information. The search stopped at a superdomain of the requested -domain. The domain is an empty nonterminal, therefore it is treated as NXRRSET -case (eg. the domain exists, but it doesn't have the requested record type). - - - - -DATASRC_MEM_SWAP swapping contents of two zone representations ('%1' and '%2') - -Debug information. The contents of two in-memory zones are being exchanged. -This is usual practice to do some manipulation in exception-safe manner -- the -new data are prepared in a different zone object and when it works, they are -swapped. The old one contains the new data and the other one can be safely -destroyed. - - - - -DATASRC_MEM_WILDCARD_CANCEL wildcard match canceled for '%1' - -Debug information. A domain above wildcard was reached, but there's something -below the requested domain. Therefore the wildcard doesn't apply here. This -behaviour is specified by RFC 1034, section 4.3.3 - - - - -DATASRC_MEM_WILDCARD_DNAME DNAME record in wildcard domain '%1' - -The software refuses to load DNAME records into a wildcard domain. It isn't -explicitly forbidden, but the protocol is ambiguous about how this should -behave and BIND 9 refuses that as well. Please describe your intention using -different tools. - - - - -DATASRC_MEM_WILDCARD_NS NS record in wildcard domain '%1' - -The software refuses to load NS records into a wildcard domain. It isn't -explicitly forbidden, but the protocol is ambiguous about how this should -behave and BIND 9 refuses that as well. Please describe your intention using -different tools. - - - - -DATASRC_META_ADD adding a data source into meta data source - -This is a debug message issued during startup or reconfiguration. -Another data source is being added into the meta data source. - - - - -DATASRC_META_ADD_CLASS_MISMATCH mismatch between classes '%1' and '%2' - -It was attempted to add a data source into a meta data source, but their -classes do not match. - - - - -DATASRC_META_REMOVE removing data source from meta data source - -Debug information. A data source is being removed from meta data source. - - - - -DATASRC_QUERY_ADD_NSEC adding NSEC record for '%1' - -Debug information. A NSEC record covering this zone is being added. - - - - -DATASRC_QUERY_ADD_NSEC3 adding NSEC3 record of zone '%1' - -Debug information. A NSEC3 record for the given zone is being added to the -response message. - - - - -DATASRC_QUERY_ADD_RRSET adding RRset '%1/%2' to message - -Debug information. An RRset is being added to the response message. - - - - -DATASRC_QUERY_ADD_SOA adding SOA of '%1' - -Debug information. A SOA record of the given zone is being added to the -authority section of the response message. - - - - -DATASRC_QUERY_AUTH_FAIL the underlying data source failed with %1 - -The underlying data source failed to answer the authoritative query. 1 means -some error, 2 is not implemented. The data source should have logged the -specific error already. - - - - -DATASRC_QUERY_BAD_REFERRAL bad referral to '%1' - -The domain lives in another zone. But it is not possible to generate referral -information for it. - - - - -DATASRC_QUERY_CACHED data for %1/%2 found in hotspot cache - -Debug information. The requested data were found in the hotspot cache, so -no query is sent to the real data source. - - - - -DATASRC_QUERY_CHECK_CACHE checking hotspot cache for '%1/%2' - -Debug information. While processing a query, lookup to the hotspot cache -is being made. - - - - -DATASRC_QUERY_COPY_AUTH copying authoritative section into message - -Debug information. The whole referral information is being copied into the -response message. - - - - -DATASRC_QUERY_DELEGATION looking for delegation on the path to '%1' - -Debug information. The software is trying to identify delegation points on the -way down to the given domain. - - - - -DATASRC_QUERY_EMPTY_CNAME CNAME at '%1' is empty - -A CNAME chain was being followed and an entry was found that pointed -to a domain name that had no RRsets associated with it. As a result, -the query cannot be answered. This indicates a problem with supplied data. - - - - -DATASRC_QUERY_EMPTY_DNAME the DNAME on '%1' is empty - -During an attempt to synthesize CNAME from this DNAME it was discovered the -DNAME is empty (it has no records). This indicates problem with supplied data. - - - - -DATASRC_QUERY_FAIL query failed - -Some subtask of query processing failed. The reason should have been reported -already and a SERVFAIL will be returned to the querying system. - - - - -DATASRC_QUERY_FOLLOW_CNAME following CNAME at '%1' - -Debug information. The domain is a CNAME (or a DNAME and a CNAME for it -has already been created) and the search is following this chain. - - - - -DATASRC_QUERY_GET_MX_ADDITIONAL addition of A/AAAA for '%1' requested by MX '%2' - -Debug information. While processing a query, a MX record was met. It -references the mentioned address, so A/AAAA records for it are looked up -and put it into the additional section. - - - - -DATASRC_QUERY_GET_NS_ADDITIONAL addition of A/AAAA for '%1' requested by NS '%2' - -Debug information. While processing a query, a NS record was met. It -references the mentioned address, so A/AAAA records for it are looked up -and put it into the additional section. - - - - -DATASRC_QUERY_GLUE_FAIL the underlying data source failed with %1 - -The underlying data source failed to answer the glue query. 1 means some error, -2 is not implemented. The data source should have logged the specific error -already. - - - - -DATASRC_QUERY_INVALID_OP invalid query operation requested - -This indicates a programmer error. The DO_QUERY was called with unknown -operation code. - - - - -DATASRC_QUERY_IS_AUTH auth query (%1/%2) - -Debug information. The last DO_QUERY is an auth query. - - - - -DATASRC_QUERY_IS_GLUE glue query (%1/%2) - -Debug information. The last DO_QUERY is a query for glue addresses. - - - - -DATASRC_QUERY_IS_NOGLUE query for non-glue addresses (%1/%2) - -Debug information. The last DO_QUERY is a query for addresses that are not -glue. - - - - -DATASRC_QUERY_IS_REF query for referral (%1/%2) - -Debug information. The last DO_QUERY is a query for referral information. - - - - -DATASRC_QUERY_IS_SIMPLE simple query (%1/%2) - -Debug information. The last DO_QUERY is a simple query. - - - - -DATASRC_QUERY_MISPLACED_TASK task of this type should not be here - -This indicates a programming error. A task was found in the internal task -queue, but this kind of task wasn't designed to be inside the queue (it should -be handled right away, not queued). - - - - -DATASRC_QUERY_MISSING_NS missing NS records for '%1' - -NS records should have been put into the authority section. However, this zone -has none. This indicates problem with provided data. - - - - -DATASRC_QUERY_MISSING_SOA the zone '%1' has no SOA - -The answer should have been a negative one (eg. of nonexistence of something). -To do so, a SOA record should be put into the authority section, but the zone -does not have one. This indicates problem with provided data. - - - - -DATASRC_QUERY_NOGLUE_FAIL the underlying data source failed with %1 - -The underlying data source failed to answer the no-glue query. 1 means some -error, 2 is not implemented. The data source should have logged the specific -error already. - - - - -DATASRC_QUERY_NO_CACHE_ANY_AUTH ignoring hotspot cache for ANY query (%1/%2 in %3 class) - -Debug information. The hotspot cache is ignored for authoritative ANY queries -for consistency reasons. - - - - -DATASRC_QUERY_NO_CACHE_ANY_SIMPLE ignoring hotspot cache for ANY query (%1/%2 in %3 class) - -Debug information. The hotspot cache is ignored for ANY queries for consistency -reasons. - - - - -DATASRC_QUERY_NO_DS_NSEC there's no DS record in the '%1' zone - -An attempt to add a NSEC record into the message failed, because the zone does -not have any DS record. This indicates problem with the provided data. - - - - -DATASRC_QUERY_NO_DS_NSEC3 there's no DS record in the '%1' zone - -An attempt to add a NSEC3 record into the message failed, because the zone does -not have any DS record. This indicates problem with the provided data. - - - - -DATASRC_QUERY_NO_ZONE no zone containing '%1' in class '%2' - -Lookup of domain failed because the data have no zone that contain the -domain. Maybe someone sent a query to the wrong server for some reason. - - - - -DATASRC_QUERY_PROCESS processing query '%1/%2' in the '%3' class - -Debug information. A sure query is being processed now. - - - - -DATASRC_QUERY_PROVE_NX_FAIL unable to prove nonexistence of '%1' - -The user wants DNSSEC and we discovered the entity doesn't exist (either -domain or the record). But there was an error getting NSEC/NSEC3 record -to prove the nonexistence. - - - - -DATASRC_QUERY_REF_FAIL the underlying data source failed with %1 - -The underlying data source failed to answer the query for referral information. -1 means some error, 2 is not implemented. The data source should have logged -the specific error already. - - - - -DATASRC_QUERY_RRSIG unable to answer RRSIG query - -The server is unable to answer a direct query for RRSIG type, but was asked -to do so. - - - - -DATASRC_QUERY_SIMPLE_FAIL the underlying data source failed with %1 - -The underlying data source failed to answer the simple query. 1 means some -error, 2 is not implemented. The data source should have logged the specific -error already. - - - - -DATASRC_QUERY_SYNTH_CNAME synthesizing CNAME from DNAME on '%1' - -This is a debug message. While answering a query, a DNAME was encountered. The -DNAME itself will be returned, along with a synthesized CNAME for clients that -do not understand the DNAME RR. - - - - -DATASRC_QUERY_TASK_FAIL task failed with %1 - -The query subtask failed. The reason should have been reported by the subtask -already. The code is 1 for error, 2 for not implemented. - - - - -DATASRC_QUERY_TOO_MANY_CNAMES CNAME chain limit exceeded at '%1' - -A CNAME led to another CNAME and it led to another, and so on. After 16 -CNAMEs, the software gave up. Long CNAME chains are discouraged, and this -might possibly be a loop as well. Note that some of the CNAMEs might have -been synthesized from DNAMEs. This indicates problem with supplied data. - - - - -DATASRC_QUERY_UNKNOWN_RESULT unknown result of subtask - -This indicates a programmer error. The answer of subtask doesn't look like -anything known. - - - - -DATASRC_QUERY_WILDCARD looking for a wildcard covering '%1' - -Debug information. A direct match wasn't found, so a wildcard covering the -domain is being looked for now. - - - - -DATASRC_QUERY_WILDCARD_FAIL error processing wildcard for '%1' - -During an attempt to cover the domain by a wildcard an error happened. The -exact kind was hopefully already reported. - - - - -DATASRC_QUERY_WILDCARD_PROVE_NX_FAIL unable to prove nonexistence of '%1' (%2) - -While processing a wildcard, it wasn't possible to prove nonexistence of the -given domain or record. The code is 1 for error and 2 for not implemented. - - - - -DATASRC_QUERY_WILDCARD_REFERRAL unable to find referral info for '%1' (%2) - -While processing a wildcard, a referral was met. But it wasn't possible to get -enough information for it. The code is 1 for error, 2 for not implemented. - - - - -DATASRC_SQLITE_CLOSE closing SQLite database - -Debug information. The SQLite data source is closing the database file. - - - - -DATASRC_SQLITE_CONNCLOSE Closing sqlite database - -The database file is no longer needed and is being closed. - - - - -DATASRC_SQLITE_CONNOPEN Opening sqlite database file '%1' - -The database file is being opened so it can start providing data. - - - - -DATASRC_SQLITE_CREATE SQLite data source created - -Debug information. An instance of SQLite data source is being created. - - - - -DATASRC_SQLITE_DESTROY SQLite data source destroyed - -Debug information. An instance of SQLite data source is being destroyed. - - - - -DATASRC_SQLITE_DROPCONN SQLite3Database is being deinitialized - -The object around a database connection is being destroyed. - - - - -DATASRC_SQLITE_ENCLOSURE looking for zone containing '%1' - -Debug information. The SQLite data source is trying to identify which zone -should hold this domain. - - - - -DATASRC_SQLITE_ENCLOSURE_NOT_FOUND no zone contains '%1' - -Debug information. The last SQLITE_ENCLOSURE query was unsuccessful; there's -no such zone in our data. - - - - -DATASRC_SQLITE_FIND looking for RRset '%1/%2' - -Debug information. The SQLite data source is looking up a resource record -set. - - - - -DATASRC_SQLITE_FINDADDRS looking for A/AAAA addresses for '%1' - -Debug information. The data source is looking up the addresses for given -domain name. - - - - -DATASRC_SQLITE_FINDADDRS_BAD_CLASS class mismatch looking for addresses ('%1' and '%2') - -The SQLite data source was looking up A/AAAA addresses, but the data source -contains different class than the query was for. - - - - -DATASRC_SQLITE_FINDEXACT looking for exact RRset '%1/%2' - -Debug information. The SQLite data source is looking up an exact resource -record. - - - - -DATASRC_SQLITE_FINDEXACT_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2') - -The SQLite data source was looking up an exact RRset, but the data source -contains different class than the query was for. - - - - -DATASRC_SQLITE_FINDREC looking for record '%1/%2' - -Debug information. The SQLite data source is looking up records of given name -and type in the database. - - - - -DATASRC_SQLITE_FINDREF looking for referral at '%1' - -Debug information. The SQLite data source is identifying if this domain is -a referral and where it goes. - - - - -DATASRC_SQLITE_FINDREF_BAD_CLASS class mismatch looking for referral ('%1' and '%2') - -The SQLite data source was trying to identify if there's a referral. But -it contains different class than the query was for. - - - - -DATASRC_SQLITE_FIND_BAD_CLASS class mismatch looking for an RRset ('%1' and '%2') - -The SQLite data source was looking up an RRset, but the data source contains -different class than the query was for. - - - - -DATASRC_SQLITE_FIND_NSEC3 looking for NSEC3 in zone '%1' for hash '%2' - -Debug information. We're trying to look up a NSEC3 record in the SQLite data -source. - - - - -DATASRC_SQLITE_FIND_NSEC3_NO_ZONE no such zone '%1' - -The SQLite data source was asked to provide a NSEC3 record for given zone. -But it doesn't contain that zone. - - - - -DATASRC_SQLITE_NEWCONN SQLite3Database is being initialized - -A wrapper object to hold database connection is being initialized. - - - - -DATASRC_SQLITE_OPEN opening SQLite database '%1' - -Debug information. The SQLite data source is loading an SQLite database in -the provided file. - - - - -DATASRC_SQLITE_PREVIOUS looking for name previous to '%1' - -This is a debug message. The name given was not found, so the program -is searching for the next name higher up the hierarchy (e.g. if -www.example.com were queried for and not found, the software searches -for the "previous" name, example.com). - - - - -DATASRC_SQLITE_PREVIOUS_NO_ZONE no zone containing '%1' - -The name given was not found, so the program is searching for the next -name higher up the hierarchy (e.g. if www.example.com were queried -for and not found, the software searches for the "previous" name, -example.com). However, this name is not contained in any zone in the -data source. This is an error since it indicates a problem in the earlier -processing of the query. - - - - -DATASRC_SQLITE_SETUP setting up SQLite database - -The database for SQLite data source was found empty. It is assumed this is the -first run and it is being initialized with current schema. It'll still contain -no data, but it will be ready for use. - - - - -DATASRC_STATIC_CLASS_NOT_CH static data source can handle CH class only - -An error message indicating that a query requesting a RR for a class other -that CH was sent to the static data source (which only handles CH queries). - - - - -DATASRC_STATIC_CREATE creating the static datasource - -Debug information. The static data source (the one holding stuff like -version.bind) is being created. - - - - -DATASRC_STATIC_FIND looking for '%1/%2' - -Debug information. This resource record set is being looked up in the static -data source. - - - - -DATASRC_UNEXPECTED_QUERY_STATE unexpected query state - -This indicates a programming error. An internal task of unknown type was -generated. - - - - -DDNS_CC_SESSION_ERROR error reading from cc channel: %1 - -There was a problem reading from the command and control channel. The -most likely cause is that the msgq process is not running. - - - - -DDNS_CC_SESSION_TIMEOUT_ERROR timeout waiting for cc response - -There was a problem reading a response from another module over the -command and control channel. The most likely cause is that the -configuration manager b10-cfgmgr is not running. - - - - -DDNS_CONFIG_ERROR error found in configuration data: %1 - -The ddns process encountered an error when installing the configuration at -startup time. Details of the error are included in the log message. - - - - -DDNS_MODULECC_SESSION_ERROR error encountered by configuration/command module: %1 - -There was a problem in the lower level module handling configuration and -control commands. This could happen for various reasons, but the most likely -cause is that the configuration database contains a syntax error and ddns -failed to start at initialization. A detailed error message from the module -will also be displayed. - - - - -DDNS_RECEIVED_SHUTDOWN_COMMAND shutdown command received - -The ddns process received a shutdown command from the command channel -and will now shut down. - - - - -DDNS_RUNNING ddns server is running and listening for updates - -The ddns process has successfully started and is now ready to receive commands -and updates. - - - - -DDNS_SHUTDOWN ddns server shutting down - -The ddns process is shutting down. It will no longer listen for new commands -or updates. Any command or update that is being addressed at this moment will -be completed, after which the process will exit. - - - - -DDNS_STOPPED ddns server has stopped - -The ddns process has successfully stopped and is no longer listening for or -handling commands or updates, and will now exit. - - - - -DDNS_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the ddns process. The -process will now shut down. - - - - -DDNS_UNCAUGHT_EXCEPTION uncaught exception of type %1: %2 - -The b10-ddns process encountered an uncaught exception and will now shut -down. This is indicative of a programming error and should not happen under -normal circumstances. The exception type and message are printed. - - - - -LIBXFRIN_DIFFERENT_TTL multiple data with different TTLs (%1, %2) on %3/%4/%5. Adjusting %2 -> %1. - -The xfrin module received an update containing multiple rdata changes for the -same RRset. But the TTLs of these don't match each other. As we combine them -together, the latter one gets overwritten to the earlier one in the sequence. - - - - -LIBXFRIN_NO_JOURNAL disabled journaling for updates to %1 on %2 - -An attempt was made to create a Diff object with journaling enabled, but -the underlying data source didn't support journaling (while still allowing -updates) and so the created object has it disabled. At a higher level this -means that the updates will be applied to the zone but subsequent IXFR requests -will result in a full zone transfer (i.e., an AXFR-style IXFR). Unless the -overhead of the full transfer is an issue this message can be ignored; -otherwise you may want to check why the journaling wasn't allowed on the -data source and either fix the issue or use a different type of data source. - - - - -LOGIMPL_ABOVE_MAX_DEBUG debug level of %1 is too high and will be set to the maximum of %2 - -A message from the interface to the underlying logger implementation reporting -that the debug level (as set by an internally-created string DEBUGn, where n -is an integer, e.g. DEBUG22) is above the maximum allowed value and has -been reduced to that value. The appearance of this message may indicate -a programming error - please submit a bug report. - - - - -LOGIMPL_BAD_DEBUG_STRING debug string '%1' has invalid format - -A message from the interface to the underlying logger implementation -reporting that an internally-created string used to set the debug level -is not of the correct format (it should be of the form DEBUGn, where n -is an integer, e.g. DEBUG22). The appearance of this message indicates -a programming error - please submit a bug report. - - - - -LOGIMPL_BELOW_MIN_DEBUG debug level of %1 is too low and will be set to the minimum of %2 - -A message from the interface to the underlying logger implementation reporting -that the debug level (as set by an internally-created string DEBUGn, where n -is an integer, e.g. DEBUG22) is below the minimum allowed value and has -been increased to that value. The appearance of this message may indicate -a programming error - please submit a bug report. - - - - -LOG_BAD_DESTINATION unrecognized log destination: %1 - -A logger destination value was given that was not recognized. The -destination should be one of "console", "file", or "syslog". - - - - -LOG_BAD_SEVERITY unrecognized log severity: %1 - -A logger severity value was given that was not recognized. The severity -should be one of "DEBUG", "INFO", "WARN", "ERROR", "FATAL" or "NONE". - - - - -LOG_BAD_STREAM bad log console output stream: %1 - -Logging has been configured so that output is written to the terminal -(console) but the stream on which it is to be written is not recognised. -Allowed values are "stdout" and "stderr". - - - - -LOG_DUPLICATE_MESSAGE_ID duplicate message ID (%1) in compiled code - -During start-up, BIND 10 detected that the given message identification -had been defined multiple times in the BIND 10 code. This indicates a -programming error; please submit a bug report. - - - - -LOG_DUPLICATE_NAMESPACE line %1: duplicate $NAMESPACE directive found - -When reading a message file, more than one $NAMESPACE directive was found. -(This directive is used to set a C++ namespace when generating header -files during software development.) Such a condition is regarded as an -error and the read will be abandoned. - - - - -LOG_INPUT_OPEN_FAIL unable to open message file %1 for input: %2 - -The program was not able to open the specified input message file for -the reason given. - - - - -LOG_INVALID_MESSAGE_ID line %1: invalid message identification '%2' - -An invalid message identification (ID) has been found during the read of -a message file. Message IDs should comprise only alphanumeric characters -and the underscore, and should not start with a digit. - - - - -LOG_NAMESPACE_EXTRA_ARGS line %1: $NAMESPACE directive has too many arguments - -The $NAMESPACE directive in a message file takes a single argument, a -namespace in which all the generated symbol names are placed. This error -is generated when the compiler finds a $NAMESPACE directive with more -than one argument. - - - - -LOG_NAMESPACE_INVALID_ARG line %1: $NAMESPACE directive has an invalid argument ('%2') - -The $NAMESPACE argument in a message file should be a valid C++ namespace. -This message is output if the simple check on the syntax of the string -carried out by the reader fails. - - - - -LOG_NAMESPACE_NO_ARGS line %1: no arguments were given to the $NAMESPACE directive - -The $NAMESPACE directive in a message file takes a single argument, -a C++ namespace in which all the generated symbol names are placed. -This error is generated when the compiler finds a $NAMESPACE directive -with no arguments. - - - - -LOG_NO_MESSAGE_ID line %1: message definition line found without a message ID - -Within a message file, message are defined by lines starting with a "%". -The rest of the line should comprise the message ID and text describing -the message. This error indicates the message compiler found a line in -the message file comprising just the "%" and nothing else. - - - - -LOG_NO_MESSAGE_TEXT line %1: line found containing a message ID ('%2') and no text - -Within a message file, message are defined by lines starting with a "%". -The rest of the line should comprise the message ID and text describing -the message. This error indicates the message compiler found a line -in the message file comprising just the "%" and message identification, -but no text. - - - - -LOG_NO_SUCH_MESSAGE could not replace message text for '%1': no such message - -During start-up a local message file was read. A line with the listed -message identification was found in the file, but the identification is -not one contained in the compiled-in message dictionary. This message -may appear a number of times in the file, once for every such unknown -message identification. - -There may be several reasons why this message may appear: - -- The message ID has been mis-spelled in the local message file. - -- The program outputting the message may not use that particular message -(e.g. it originates in a module not used by the program.) - -- The local file was written for an earlier version of the BIND 10 software -and the later version no longer generates that message. - -Whatever the reason, there is no impact on the operation of BIND 10. - - - - -LOG_OPEN_OUTPUT_FAIL unable to open %1 for output: %2 - -Originating within the logging code, the program was not able to open -the specified output file for the reason given. - - - - -LOG_PREFIX_EXTRA_ARGS line %1: $PREFIX directive has too many arguments - -Within a message file, the $PREFIX directive takes a single argument, -a prefix to be added to the symbol names when a C++ file is created. -This error is generated when the compiler finds a $PREFIX directive with -more than one argument. - -Note: the $PREFIX directive is deprecated and will be removed in a future -version of BIND 10. - - - - -LOG_PREFIX_INVALID_ARG line %1: $PREFIX directive has an invalid argument ('%2') - -Within a message file, the $PREFIX directive takes a single argument, -a prefix to be added to the symbol names when a C++ file is created. -As such, it must adhere to restrictions on C++ symbol names (e.g. may -only contain alphanumeric characters or underscores, and may nor start -with a digit). A $PREFIX directive was found with an argument (given -in the message) that violates those restrictions. - -Note: the $PREFIX directive is deprecated and will be removed in a future -version of BIND 10. - - - - -LOG_READING_LOCAL_FILE reading local message file %1 - -This is an informational message output by BIND 10 when it starts to read -a local message file. (A local message file may replace the text of -one of more messages; the ID of the message will not be changed though.) - - - - -LOG_READ_ERROR error reading from message file %1: %2 - -The specified error was encountered reading from the named message file. - - - - -LOG_UNRECOGNISED_DIRECTIVE line %1: unrecognised directive '%2' - -Within a message file, a line starting with a dollar symbol was found -(indicating the presence of a directive) but the first word on the line -(shown in the message) was not recognised. - - - - -LOG_WRITE_ERROR error writing to %1: %2 - -The specified error was encountered by the message compiler when writing -to the named output file. - - - - -NOTIFY_OUT_DATASRC_ACCESS_FAILURE failed to get access to data source: %1 - -notify_out failed to get access to one of configured data sources. -Detailed error is shown in the log message. This can be either a -configuration error or installation setup failure. - - - - -NOTIFY_OUT_DATASRC_ZONE_NOT_FOUND Zone %1 is not found - -notify_out attempted to get slave information of a zone but the zone -isn't found in the expected data source. This shouldn't happen, -because notify_out first identifies a list of available zones before -this process. So this means some critical inconsistency in the data -source or software bug. - - - - -NOTIFY_OUT_INVALID_ADDRESS invalid address %1#%2: %3 - -The notify_out library tried to send a notify message to the given -address, but it appears to be an invalid address. The configuration -for secondary nameservers might contain a typographic error, or a -different BIND 10 module has forgotten to validate its data before -sending this module a notify command. As such, this should normally -not happen, and points to an oversight in a different module. - - - - -NOTIFY_OUT_REPLY_BAD_OPCODE bad opcode in notify reply from %1#%2: %3 - -The notify_out library sent a notify message to the nameserver at -the given address, but the response did not have the opcode set to -NOTIFY. The opcode in the response is printed. Since there was a -response, no more notifies will be sent to this server for this -notification event. - - - - -NOTIFY_OUT_REPLY_BAD_QID bad QID in notify reply from %1#%2: got %3, should be %4 - -The notify_out library sent a notify message to the nameserver at -the given address, but the query id in the response does not match -the one we sent. Since there was a response, no more notifies will -be sent to this server for this notification event. - - - - -NOTIFY_OUT_REPLY_BAD_QUERY_NAME bad query name in notify reply from %1#%2: got %3, should be %4 - -The notify_out library sent a notify message to the nameserver at -the given address, but the query name in the response does not match -the one we sent. Since there was a response, no more notifies will -be sent to this server for this notification event. - - - - -NOTIFY_OUT_REPLY_QR_NOT_SET QR flags set to 0 in reply to notify from %1#%2 - -The notify_out library sent a notify message to the namesever at the -given address, but the reply did not have the QR bit set to one. -Since there was a response, no more notifies will be sent to this -server for this notification event. - - - - -NOTIFY_OUT_REPLY_UNCAUGHT_EXCEPTION uncaught exception: %1 - -There was an uncaught exception in the handling of a notify reply -message, either in the message parser, or while trying to extract data -from the parsed message. The error is printed, and notify_out will -treat the response as a bad message, but this does point to a -programming error, since all exceptions should have been caught -explicitly. Please file a bug report. Since there was a response, -no more notifies will be sent to this server for this notification -event. - - - - -NOTIFY_OUT_RETRY_EXCEEDED notify to %1#%2: number of retries (%3) exceeded - -The maximum number of retries for the notify target has been exceeded. -Either the address of the secondary nameserver is wrong, or it is not -responding. - - - - -NOTIFY_OUT_SENDING_NOTIFY sending notify to %1#%2 - -A notify message is sent to the secondary nameserver at the given -address. - - - - -NOTIFY_OUT_SOCKET_ERROR socket error sending notify to %1#%2: %3 - -There was a network error while trying to send a notify message to -the given address. The address might be unreachable. The socket -error is printed and should provide more information. - - - - -NOTIFY_OUT_SOCKET_RECV_ERROR socket error reading notify reply from %1#%2: %3 - -There was a network error while trying to read a notify reply -message from the given address. The socket error is printed and should -provide more information. - - - - -NOTIFY_OUT_TIMEOUT retry notify to %1#%2 - -The notify message to the given address (noted as address#port) has -timed out, and the message will be resent until the max retry limit -is reached. - - - - -NOTIFY_OUT_ZONE_BAD_SOA Zone %1 is invalid in terms of SOA - -This is a warning issued when the notify_out module finds a zone that -doesn't have an SOA RR or has multiple SOA RRs. Notify message won't -be sent to such a zone. - - - - -NOTIFY_OUT_ZONE_NO_NS Zone %1 doesn't have NS RR - -This is a warning issued when the notify_out module finds a zone that -doesn't have an NS RR. Notify message won't be sent to such a zone. - - - - -NSAS_EMPTY_RESPONSE response to query for %1 returned an empty answer section - -The NSAS (nameserver address store - part of the resolver) made a query -for information it needed. The query completed successfully but the -answer section in the response was empty. - - - - -NSAS_ERROR_RESPONSE error response of %1 returned in query for %2 - -The NSAS (nameserver address store - part of the resolver) made a query -for information it needed. The query completed successfully but the -RCODE in the response was something other than NOERROR. - - - - -NSAS_FIND_NS_ADDRESS asking resolver to obtain A and AAAA records for %1 - -A debug message issued when the NSAS (nameserver address store - part -of the resolver) is making a callback into the resolver to retrieve the -address records for the specified nameserver. - - - - -NSAS_FOUND_ADDRESS found address %1 for %2 - -A debug message issued when the NSAS (nameserver address store - part -of the resolver) has retrieved the given address for the specified -nameserver through an external query. - - - - -NSAS_LOOKUP_CANCEL lookup for zone %1 has been canceled - -A debug message issued when an NSAS (nameserver address store - part of -the resolver) lookup for a zone has been canceled. - - - - -NSAS_NS_LOOKUP_FAIL failed to lookup any %1 for %2 - -A debug message issued when the NSAS (nameserver address store - part of -the resolver) has been unable to retrieve the specified resource record -for the specified nameserver. This is not necessarily a problem - the -nameserver may be unreachable, in which case the NSAS will try other -nameservers in the zone. - - - - -NSAS_NULL_RESPONSE got null message in success callback for query for %1 - -The NSAS (nameserver address store - part of the resolver) made a query -for information it needed. The query completed successfully, but the -message passed to the callback was null. - -This message indicates an internal error in the NSAS. Please raise a -bug report. - - - - -NSAS_SEARCH_ZONE_NS searching NSAS for nameservers for zone %1 - -A debug message output when a call is made to the NSAS (nameserver -address store - part of the resolver) to obtain the nameservers for -the specified zone. - - - - -NSAS_UPDATE_RTT update RTT for %1: was %2 ms, is now %3 ms - -A NSAS (nameserver address store - part of the resolver) debug message -reporting the update of a round-trip time (RTT) for a query made to the -specified nameserver. The RTT has been updated using the value given -and the new RTT is displayed. (The RTT is subject to a calculation that -damps out sudden changes. As a result, the new RTT used by the NSAS in -future decisions of which nameserver to use is not necessarily equal to -the RTT reported.) - - - - -NSAS_WRONG_ANSWER queried for %1 RR of type/class %2/%3, received response %4/%5 - -A NSAS (nameserver address store - part of the resolver) made a query for -a resource record of a particular type and class, but instead received -an answer with a different given type and class. - -This message indicates an internal error in the NSAS. Please raise a -bug report. - - - - -RESLIB_ANSWER answer received in response to query for <%1> - -A debug message reporting that an answer has been received to an upstream -query for the specified question. Previous debug messages will have -indicated the server to which the question was sent. - - - - -RESLIB_CNAME CNAME received in response to query for <%1> - -A debug message recording that CNAME response has been received to an -upstream query for the specified question. Previous debug messages will -have indicated the server to which the question was sent. - - - - -RESLIB_DEEPEST did not find <%1> in cache, deepest delegation found is %2 - -A debug message, a cache lookup did not find the specified <name, -class, type> tuple in the cache; instead, the deepest delegation found -is indicated. - - - - -RESLIB_EMPTY_RESPONSE empty response received to query for <%1> - -A debug message, the response to the specified query from an upstream -nameserver did not contain anything in the answer or authority sections, -although in all other respects it was a valid response. A SERVFAIL will -be returned to the system making the original query. - - - - -RESLIB_ERROR_RESPONSE unspecified error received in response to query for <%1> - -A debug message, the response to the specified query to an upstream -nameserver indicated that the response was classified as an erroneous -response, but that the nature of the error cannot be identified. -A SERVFAIL will be returned to the system making the original query. - - - - -RESLIB_EXTRADATA_RESPONSE extra data in response to query for <%1> - -A debug message indicating that the response to the specified query -from an upstream nameserver contained too much data. This can happen if -an ANY query was sent and the answer section in the response contained -multiple RRs with different names. A SERVFAIL will be returned to the -system making the original query. - - - - -RESLIB_FOLLOW_CNAME following CNAME chain to <%1> - -A debug message, a CNAME response was received and another query is -being issued for the <name, class, type> tuple. - - - - -RESLIB_INVALID_NAMECLASS_RESPONSE invalid name or class in response to query for <%1> - -A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) contained either -an answer not matching the query name or an answer having a different -class to that queried for. A SERVFAIL will be returned to the system -making the original query. - - - - -RESLIB_INVALID_QNAME_RESPONSE invalid name or class in response to query for <%1> - -A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) contained a name -in the question section that did not match that of the query. A SERVFAIL -will be returned to the system making the original query. - - - - -RESLIB_INVALID_TYPE_RESPONSE invalid name or class in response to query for <%1> - -A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) contained an -invalid type field. A SERVFAIL will be returned to the system making -the original query. - - - - -RESLIB_LONG_CHAIN CNAME received in response to query for <%1>: CNAME chain length exceeded - -A debug message recording that a CNAME response has been received to an upstream -query for the specified question (Previous debug messages will have indicated -the server to which the question was sent). However, receipt of this CNAME -has meant that the resolver has exceeded the CNAME chain limit (a CNAME chain -is where on CNAME points to another) and so an error is being returned. - - - - -RESLIB_MULTIPLE_CLASS_RESPONSE response to query for <%1> contained multiple RRsets with different classes - -A debug message reporting that the response to an upstream query for -the specified name contained multiple RRsets in the answer and not all -were of the same class. This is a violation of the standard and so a -SERVFAIL will be returned. - - - - -RESLIB_NOTSINGLE_RESPONSE response to query for <%1> was not a response - -A debug message, the response to the specified query from an upstream -nameserver was a CNAME that had mutiple RRs in the RRset. This is -an invalid response according to the standards so a SERVFAIL will be -returned to the system making the original query. - - - - -RESLIB_NOT_ONE_QNAME_RESPONSE not one question in response to query for <%1> - -A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) did not contain -one name in the question section as required by the standard. A SERVFAIL -will be returned to the system making the original query. - - - - -RESLIB_NOT_RESPONSE response to query for <%1> was not a response - -A debug message, the response to the specified query from an upstream -nameserver (as identified by the ID of the response) did not have the QR -bit set (thus indicating that the packet was a query, not a response). -A SERVFAIL will be returned to the system making the original query. - - - - -RESLIB_NO_NS_RRSET no NS RRSet in referral response received to query for <%1> - -A debug message, this indicates that a response was received for the specified -query and was categorized as a referral. However, the received message did -not contain any NS RRsets. This may indicate a programming error in the -response classification code. - - - - -RESLIB_NSAS_LOOKUP looking up nameserver for zone %1 in the NSAS - -A debug message, the RunningQuery object is querying the NSAS for the -nameservers for the specified zone. - - - - -RESLIB_NXDOM_NXRR NXDOMAIN/NXRRSET received in response to query for <%1> - -A debug message recording that either a NXDOMAIN or an NXRRSET response has -been received to an upstream query for the specified question. Previous debug -messages will have indicated the server to which the question was sent. - - - - -RESLIB_OPCODE_RESPONSE response to query for <%1> did not have query opcode - -A debug message, the response to the specified query from an upstream -nameserver was a response that did not have the opcode set to that of -a query. According to the standards, this is an invalid response to -the query that was made, so a SERVFAIL will be returned to the system -making the original query. - - - - -RESLIB_PROTOCOL protocol error in answer for %1: %3 - -A debug message indicating that a protocol error was received. As there -are no retries left, an error will be reported. - - - - -RESLIB_PROTOCOL_RETRY protocol error in answer for %1: %2 (retries left: %3) - -A debug message indicating that a protocol error was received and that -the resolver is repeating the query to the same nameserver. After this -repeated query, there will be the indicated number of retries left. - - - - -RESLIB_RCODE_ERROR response to query for <%1> returns RCODE of %2 - -A debug message, the response to the specified query indicated an error -that is not covered by a specific code path. A SERVFAIL will be returned. - - - - -RESLIB_RECQ_CACHE_FIND found <%1> in the cache (resolve() instance %2) - -This is a debug message and indicates that a RecursiveQuery object found the -the specified <name, class, type> tuple in the cache. The instance number -at the end of the message indicates which of the two resolve() methods has -been called. - - - - -RESLIB_RECQ_CACHE_NO_FIND did not find <%1> in the cache, starting RunningQuery (resolve() instance %2) - -This is a debug message and indicates that the look in the cache made by the -RecursiveQuery::resolve() method did not find an answer, so a new RunningQuery -object has been created to resolve the question. The instance number at -the end of the message indicates which of the two resolve() methods has -been called. - - - - -RESLIB_REFERRAL referral received in response to query for <%1> - -A debug message recording that a referral response has been received to an -upstream query for the specified question. Previous debug messages will -have indicated the server to which the question was sent. - - - - -RESLIB_REFER_ZONE referred to zone %1 - -A debug message indicating that the last referral message was to the specified -zone. - - - - -RESLIB_RESOLVE asked to resolve <%1> (resolve() instance %2) - -A debug message, the RecursiveQuery::resolve method has been called to resolve -the specified <name, class, type> tuple. The first action will be to lookup -the specified tuple in the cache. The instance number at the end of the -message indicates which of the two resolve() methods has been called. - - - - -RESLIB_RRSET_FOUND found single RRset in the cache when querying for <%1> (resolve() instance %2) - -A debug message, indicating that when RecursiveQuery::resolve queried the -cache, a single RRset was found which was put in the answer. The instance -number at the end of the message indicates which of the two resolve() -methods has been called. - - - - -RESLIB_RTT round-trip time of last query calculated as %1 ms - -A debug message giving the round-trip time of the last query and response. - - - - -RESLIB_RUNQ_CACHE_FIND found <%1> in the cache - -This is a debug message and indicates that a RunningQuery object found -the specified <name, class, type> tuple in the cache. - - - - -RESLIB_RUNQ_CACHE_LOOKUP looking up up <%1> in the cache - -This is a debug message and indicates that a RunningQuery object has made -a call to its doLookup() method to look up the specified <name, class, type> -tuple, the first action of which will be to examine the cache. - - - - -RESLIB_RUNQ_FAIL failure callback - nameservers are unreachable - -A debug message indicating that a RunningQuery's failure callback has been -called because all nameservers for the zone in question are unreachable. - - - - -RESLIB_RUNQ_SUCCESS success callback - sending query to %1 - -A debug message indicating that a RunningQuery's success callback has been -called because a nameserver has been found, and that a query is being sent -to the specified nameserver. - - - - -RESLIB_TCP_TRUNCATED TCP response to query for %1 was truncated - -This is a debug message logged when a response to the specified query to an -upstream nameserver returned a response with the TC (truncation) bit set. This -is treated as an error by the code. - - - - -RESLIB_TEST_SERVER setting test server to %1(%2) - -This is a warning message only generated in unit tests. It indicates -that all upstream queries from the resolver are being routed to the -specified server, regardless of the address of the nameserver to which -the query would normally be routed. If seen during normal operation, -please submit a bug report. - - - - -RESLIB_TEST_UPSTREAM sending upstream query for <%1> to test server at %2 - -This is a debug message and should only be seen in unit tests. A query for -the specified <name, class, type> tuple is being sent to a test nameserver -whose address is given in the message. - - - - -RESLIB_TIMEOUT query <%1> to %2 timed out - -A debug message indicating that the specified upstream query has timed out and -there are no retries left. - - - - -RESLIB_TIMEOUT_RETRY query <%1> to %2 timed out, re-trying (retries left: %3) - -A debug message indicating that the specified query has timed out and that -the resolver is repeating the query to the same nameserver. After this -repeated query, there will be the indicated number of retries left. - - - - -RESLIB_TRUNCATED response to query for <%1> was truncated, re-querying over TCP - -A debug message, this indicates that the response to the specified query was -truncated and that the resolver will be re-querying over TCP. There are -various reasons why responses may be truncated, so this message is normal and -gives no cause for concern. - - - - -RESLIB_UPSTREAM sending upstream query for <%1> to %2 - -A debug message indicating that a query for the specified <name, class, type> -tuple is being sent to a nameserver whose address is given in the message. - - - - -RESOLVER_AXFR_TCP AXFR request received over TCP - -This is a debug message output when the resolver received a request for -an AXFR (full transfer of a zone) over TCP. Only authoritative servers -are able to handle AXFR requests, so the resolver will return an error -message to the sender with the RCODE set to NOTIMP. - - - - -RESOLVER_AXFR_UDP AXFR request received over UDP - -This is a debug message output when the resolver received a request for -an AXFR (full transfer of a zone) over UDP. Only authoritative servers -are able to handle AXFR requests (and in any case, an AXFR request should -be sent over TCP), so the resolver will return an error message to the -sender with the RCODE set to NOTIMP. - - - - -RESOLVER_CLIENT_TIME_SMALL client timeout of %1 is too small - -During the update of the resolver's configuration parameters, the value -of the client timeout was found to be too small. The configuration -update was abandoned and the parameters were not changed. - - - - -RESOLVER_CONFIG_CHANNEL configuration channel created - -This is a debug message output when the resolver has successfully -established a connection to the configuration channel. - - - - -RESOLVER_CONFIG_ERROR error in configuration: %1 - -An error was detected in a configuration update received by the -resolver. This may be in the format of the configuration message (in -which case this is a programming error) or it may be in the data supplied -(in which case it is a user error). The reason for the error, included -in the message, will give more details. The configuration update is -not applied and the resolver parameters were not changed. - - - - -RESOLVER_CONFIG_LOADED configuration loaded - -This is a debug message output when the resolver configuration has been -successfully loaded. - - - - -RESOLVER_CONFIG_UPDATED configuration updated: %1 - -This is a debug message output when the resolver configuration is being -updated with the specified information. - - - - -RESOLVER_CREATED main resolver object created - -This is a debug message indicating that the main resolver object has -been created. - - - - -RESOLVER_DNS_MESSAGE_RECEIVED DNS message received: %1 - -This is a debug message from the resolver listing the contents of a -received DNS message. - - - - -RESOLVER_DNS_MESSAGE_SENT DNS message of %1 bytes sent: %2 - -This is a debug message containing details of the response returned by -the resolver to the querying system. - - - - -RESOLVER_FAILED resolver failed, reason: %1 - -This is an error message output when an unhandled exception is caught -by the resolver. After this, the resolver will shut itself down. -Please submit a bug report. - - - - -RESOLVER_FORWARD_ADDRESS setting forward address %1(%2) - -If the resolver is running in forward mode, this message will appear -during startup to list the forward address. If multiple addresses are -specified, it will appear once for each address. - - - - -RESOLVER_FORWARD_QUERY processing forward query - -This is a debug message indicating that a query received by the resolver -has passed a set of checks (message is well-formed, it is allowed by the -ACL, it is a supported opcode, etc.) and is being forwarded to upstream -servers. - - - - -RESOLVER_HEADER_ERROR message received, exception when processing header: %1 - -This is a debug message from the resolver noting that an exception -occurred during the processing of a received packet. The packet has -been dropped. - - - - -RESOLVER_IXFR IXFR request received - -This is a debug message indicating that the resolver received a request -for an IXFR (incremental transfer of a zone). Only authoritative servers -are able to handle IXFR requests, so the resolver will return an error -message to the sender with the RCODE set to NOTIMP. - - - - -RESOLVER_LOOKUP_TIME_SMALL lookup timeout of %1 is too small - -During the update of the resolver's configuration parameters, the value -of the lookup timeout was found to be too small. The configuration -update will not be applied. - - - - -RESOLVER_MESSAGE_ERROR error parsing received message: %1 - returning %2 - -This is a debug message noting that parsing of the body of a received -message by the resolver failed due to some error (although the parsing of -the header succeeded). The message parameters give a textual description -of the problem and the RCODE returned. - - - - -RESOLVER_NEGATIVE_RETRIES negative number of retries (%1) specified in the configuration - -This error is issued when a resolver configuration update has specified -a negative retry count: only zero or positive values are valid. The -configuration update was abandoned and the parameters were not changed. - - - - -RESOLVER_NON_IN_PACKET non-IN class request received, returning REFUSED message - -This debug message is issued when resolver has received a DNS packet that -was not IN (Internet) class. The resolver cannot handle such packets, -so is returning a REFUSED response to the sender. - - - - -RESOLVER_NORMAL_QUERY processing normal query - -This is a debug message indicating that the query received by the resolver -has passed a set of checks (message is well-formed, it is allowed by the -ACL, it is a supported opcode, etc.) and is being processed by the resolver. - - - - -RESOLVER_NOTIFY_RECEIVED NOTIFY arrived but server is not authoritative - -The resolver has received a NOTIFY message. As the server is not -authoritative it cannot process it, so it returns an error message to -the sender with the RCODE set to NOTAUTH. - - - - -RESOLVER_NOT_ONE_QUESTION query contained %1 questions, exactly one question was expected - -This debug message indicates that the resolver received a query that -contained the number of entries in the question section detailed in -the message. This is a malformed message, as a DNS query must contain -only one question. The resolver will return a message to the sender -with the RCODE set to FORMERR. - - - - -RESOLVER_NO_ROOT_ADDRESS no root addresses available - -A warning message issued during resolver startup, this indicates that -no root addresses have been set. This may be because the resolver will -get them from a priming query. - - - - -RESOLVER_PARSE_ERROR error parsing received message: %1 - returning %2 - -This is a debug message noting that the resolver received a message and -the parsing of the body of the message failed due to some non-protocol -related reason (although the parsing of the header succeeded). -The message parameters give a textual description of the problem and -the RCODE returned. - - - - -RESOLVER_PRINT_COMMAND print message command, arguments are: %1 - -This debug message is logged when a "print_message" command is received -by the resolver over the command channel. - - - - -RESOLVER_PROTOCOL_ERROR protocol error parsing received message: %1 - returning %2 - -This is a debug message noting that the resolver received a message and -the parsing of the body of the message failed due to some protocol error -(although the parsing of the header succeeded). The message parameters -give a textual description of the problem and the RCODE returned. - - - - -RESOLVER_QUERY_ACCEPTED query accepted: '%1/%2/%3' from %4 - -This debug message is produced by the resolver when an incoming query -is accepted in terms of the query ACL. The log message shows the query -in the form of <query name>/<query type>/<query class>, and the client -that sends the query in the form of <Source IP address>#<source port>. - - - - -RESOLVER_QUERY_DROPPED query dropped: '%1/%2/%3' from %4 - -This is an informational message that indicates an incoming query has -been dropped by the resolver because of the query ACL. Unlike the -RESOLVER_QUERY_REJECTED case, the server does not return any response. -The log message shows the query in the form of <query name>/<query -type>/<query class>, and the client that sends the query in the form of -<Source IP address>#<source port>. - - - - -RESOLVER_QUERY_REJECTED query rejected: '%1/%2/%3' from %4 - -This is an informational message that indicates an incoming query has -been rejected by the resolver because of the query ACL. This results -in a response with an RCODE of REFUSED. The log message shows the query -in the form of <query name>/<query type>/<query class>, and the client -that sends the query in the form of <Source IP address>#<source port>. - - - - -RESOLVER_QUERY_SETUP query setup - -This is a debug message noting that the resolver is creating a -RecursiveQuery object. - - - - -RESOLVER_QUERY_SHUTDOWN query shutdown - -This is a debug message noting that the resolver is destroying a -RecursiveQuery object. - - - - -RESOLVER_QUERY_TIME_SMALL query timeout of %1 is too small - -During the update of the resolver's configuration parameters, the value -of the query timeout was found to be too small. The configuration -parameters were not changed. - - - - -RESOLVER_RECEIVED_MESSAGE resolver has received a DNS message - -This is a debug message indicating that the resolver has received a -DNS message. Depending on the debug settings, subsequent log output -will indicate the nature of the message. - - - - -RESOLVER_RECURSIVE running in recursive mode - -This is an informational message that appears at startup noting that -the resolver is running in recursive mode. - - - - -RESOLVER_SERVICE_CREATED service object created - -This debug message is output when resolver creates the main service object -(which handles the received queries). - - - - -RESOLVER_SET_PARAMS query timeout: %1, client timeout: %2, lookup timeout: %3, retry count: %4 - -This debug message lists the parameters being set for the resolver. These are: -query timeout: the timeout (in ms) used for queries originated by the resolver -to upstream servers. Client timeout: the interval to resolve a query by -a client: after this time, the resolver sends back a SERVFAIL to the client -whilst continuing to resolve the query. Lookup timeout: the time at which the -resolver gives up trying to resolve a query. Retry count: the number of times -the resolver will retry a query to an upstream server if it gets a timeout. - -The client and lookup timeouts require a bit more explanation. The -resolution of the client query might require a large number of queries to -upstream nameservers. Even if none of these queries timeout, the total time -taken to perform all the queries may exceed the client timeout. When this -happens, a SERVFAIL is returned to the client, but the resolver continues -with the resolution process; data received is added to the cache. However, -there comes a time - the lookup timeout - when even the resolver gives up. -At this point it will wait for pending upstream queries to complete or -timeout and drop the query. - - - - -RESOLVER_SET_QUERY_ACL query ACL is configured - -This debug message is generated when a new query ACL is configured for -the resolver. - - - - -RESOLVER_SET_ROOT_ADDRESS setting root address %1(%2) - -This message gives the address of one of the root servers used by the -resolver. It is output during startup and may appear multiple times, -once for each root server address. - - - - -RESOLVER_SHUTDOWN resolver shutdown complete - -This informational message is output when the resolver has shut down. - - - - -RESOLVER_STARTED resolver started - -This informational message is output by the resolver when all initialization -has been completed and it is entering its main loop. - - - - -RESOLVER_STARTING starting resolver with command line '%1' - -An informational message, this is output when the resolver starts up. - - - - -RESOLVER_UNEXPECTED_RESPONSE received unexpected response, ignoring - -This is a debug message noting that the resolver received a DNS response -packet on the port on which is it listening for queries. The packet -has been ignored. - - - - -RESOLVER_UNSUPPORTED_OPCODE opcode %1 not supported by the resolver - -This is debug message output when the resolver received a message with an -unsupported opcode (it can only process QUERY opcodes). It will return -a message to the sender with the RCODE set to NOTIMP. - - - - -SOCKETREQUESTOR_CREATED Socket requestor created - -Debug message. A socket requesor (client of the socket creator) is created -for the corresponding application. Normally this should happen at most -one time throughout the lifetime of the application. - - - - -SOCKETREQUESTOR_DESTROYED Socket requestor destoryed - -Debug message. The socket requestor created at SOCKETREQUESTOR_CREATED -has been destroyed. This event is generally unexpected other than in -test cases. - - - - -SOCKETREQUESTOR_GETSOCKET Received a %1 socket for [%2]:%3, FD=%4, token=%5, path=%6 - -Debug message. The socket requestor for the corresponding application -has requested a socket for a set of address, port and protocol (shown -in the log message) and successfully got it from the creator. The -corresponding file descriptor and the associated "token" (an internal -ID used between the creator and requestor) are shown in the log -message. - - - - -SOCKETREQUESTOR_RELEASESOCKET Released a socket of token %1 - -Debug message. The socket requestor has released a socket passed by -the creator. The associated token of the socket is shown in the -log message. If the corresponding SOCKETREQUESTOR_GETSOCKET was logged -more detailed information of the socket can be identified by matching -the token. - - - - -SRVCOMM_ADDRESSES_NOT_LIST the address and port specification is not a list in %1 - -This points to an error in configuration. What was supposed to be a list of -IP address - port pairs isn't a list at all but something else. - - - - -SRVCOMM_ADDRESS_FAIL failed to listen on addresses (%1) - -The server failed to bind to one of the address/port pair it should according -to configuration, for reason listed in the message (usually because that pair -is already used by other service or missing privileges). The server will try -to recover and bind the address/port pairs it was listening to before (if any). - - - - -SRVCOMM_ADDRESS_MISSING address specification is missing "address" or "port" element in %1 - -This points to an error in configuration. An address specification in the -configuration is missing either an address or port and so cannot be used. The -specification causing the error is given in the message. - - - - -SRVCOMM_ADDRESS_TYPE address specification type is invalid in %1 - -This points to an error in configuration. An address specification in the -configuration malformed. The specification causing the error is given in the -message. A valid specification contains an address part (which must be a string -and must represent a valid IPv4 or IPv6 address) and port (which must be an -integer in the range valid for TCP/UDP ports on your system). - - - - -SRVCOMM_ADDRESS_UNRECOVERABLE failed to recover original addresses also (%1) - -The recovery of old addresses after SRVCOMM_ADDRESS_FAIL also failed for -the reason listed. - -The condition indicates problems with the server and/or the system on -which it is running. The server will continue running to allow -reconfiguration, but will not be listening on any address or port until -an administrator does so. - - - - -SRVCOMM_ADDRESS_VALUE address to set: %1#%2 - -Debug message. This lists one address and port value of the set of -addresses we are going to listen on (eg. there will be one log message -per pair). This appears only after SRVCOMM_SET_LISTEN, but might -be hidden, as it has higher debug level. - - - - -SRVCOMM_KEYS_DEINIT deinitializing TSIG keyring - -Debug message indicating that the server is deinitializing the TSIG keyring. - - - - -SRVCOMM_KEYS_INIT initializing TSIG keyring - -Debug message indicating that the server is initializing the global TSIG -keyring. This should be seen only at server start. - - - - -SRVCOMM_KEYS_UPDATE updating TSIG keyring - -Debug message indicating new keyring is being loaded from configuration (either -on startup or as a result of configuration update). - - - - -SRVCOMM_PORT_RANGE port out of valid range (%1 in %2) - -This points to an error in configuration. The port in an address -specification is outside the valid range of 0 to 65535. - - - - -SRVCOMM_SET_LISTEN setting addresses to listen to - -Debug message, noting that the server is about to start listening on a -different set of IP addresses and ports than before. - - - - -STATHTTPD_BAD_OPTION_VALUE bad command line argument: %1 - -The stats-httpd module was called with a bad command-line argument -and will not start. - - - - -STATHTTPD_CC_SESSION_ERROR error connecting to message bus: %1 - -The stats-httpd module was unable to connect to the BIND 10 command -and control bus. A likely problem is that the message bus daemon -(b10-msgq) is not running. The stats-httpd module will now shut down. - - - - -STATHTTPD_CLOSING closing %1#%2 - -The stats-httpd daemon will stop listening for requests on the given -address and port number. - - - - -STATHTTPD_CLOSING_CC_SESSION stopping cc session - -Debug message indicating that the stats-httpd module is disconnecting -from the command and control bus. - - - - -STATHTTPD_HANDLE_CONFIG reading configuration: %1 - -The stats-httpd daemon has received new configuration data and will now -process it. The (changed) data is printed. - - - - -STATHTTPD_RECEIVED_SHUTDOWN_COMMAND shutdown command received - -A shutdown command was sent to the stats-httpd module, and it will -now shut down. - - - - -STATHTTPD_RECEIVED_STATUS_COMMAND received command to return status - -A status command was sent to the stats-httpd module, and it will -respond with 'Stats Httpd is up.' and its PID. - - - - -STATHTTPD_RECEIVED_UNKNOWN_COMMAND received unknown command: %1 - -An unknown command has been sent to the stats-httpd module. The -stats-httpd module will respond with an error, and the command will -be ignored. - - - - -STATHTTPD_SERVER_DATAERROR HTTP server data error: %1 - -An internal error occurred while handling an HTTP request. An HTTP 404 -response will be sent back, and the specific error is printed. This -is an error condition that likely points the specified data -corresponding to the requested URI is incorrect. - - - - -STATHTTPD_SERVER_ERROR HTTP server error: %1 - -An internal error occurred while handling an HTTP request. An HTTP 500 -response will be sent back, and the specific error is printed. This -is an error condition that likely points to a module that is not -responding correctly to statistic requests. - - - - -STATHTTPD_SERVER_INIT_ERROR HTTP server initialization error: %1 - -There was a problem initializing the HTTP server in the stats-httpd -module upon receiving its configuration data. The most likely cause -is a port binding problem or a bad configuration value. The specific -error is printed in the message. The new configuration is ignored, -and an error is sent back. - - - - -STATHTTPD_SHUTDOWN shutting down - -The stats-httpd daemon is shutting down. - - - - -STATHTTPD_STARTED listening on %1#%2 - -The stats-httpd daemon will now start listening for requests on the -given address and port number. - - - - -STATHTTPD_STARTING_CC_SESSION starting cc session - -Debug message indicating that the stats-httpd module is connecting to -the command and control bus. - - - - -STATHTTPD_START_SERVER_INIT_ERROR HTTP server initialization error: %1 - -There was a problem initializing the HTTP server in the stats-httpd -module upon startup. The most likely cause is that it was not able -to bind to the listening port. The specific error is printed, and the -module will shut down. - - - - -STATHTTPD_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the stats-httpd -daemon. The daemon will now shut down. - - - - -STATHTTPD_UNKNOWN_CONFIG_ITEM unknown configuration item: %1 - -The stats-httpd daemon received a configuration update from the -configuration manager. However, one of the items in the -configuration is unknown. The new configuration is ignored, and an -error is sent back. As possible cause is that there was an upgrade -problem, and the stats-httpd version is out of sync with the rest of -the system. - - - - -STATS_BAD_OPTION_VALUE bad command line argument: %1 - -The stats module was called with a bad command-line argument and will -not start. - - - - -STATS_CC_SESSION_ERROR error connecting to message bus: %1 - -The stats module was unable to connect to the BIND 10 command and -control bus. A likely problem is that the message bus daemon -(b10-msgq) is not running. The stats module will now shut down. - - - - -STATS_RECEIVED_NEW_CONFIG received new configuration: %1 - -This debug message is printed when the stats module has received a -configuration update from the configuration manager. - - - - -STATS_RECEIVED_SHOWSCHEMA_ALL_COMMAND received command to show all statistics schema - -The stats module received a command to show all statistics schemas of all modules. - - - - -STATS_RECEIVED_SHOWSCHEMA_NAME_COMMAND received command to show statistics schema for %1 - -The stats module received a command to show the specified statistics schema of the specified module. - - - - -STATS_RECEIVED_SHOW_ALL_COMMAND received command to show all statistics - -The stats module received a command to show all statistics that it has -collected. - - - - -STATS_RECEIVED_SHOW_NAME_COMMAND received command to show statistics for %1 - -The stats module received a command to show the statistics that it has -collected for the given item. - - - - -STATS_RECEIVED_SHUTDOWN_COMMAND shutdown command received - -A shutdown command was sent to the stats module and it will now shut down. - - - - -STATS_RECEIVED_STATUS_COMMAND received command to return status - -A status command was sent to the stats module. It will return a -response indicating that it is running normally. - - - - -STATS_RECEIVED_UNKNOWN_COMMAND received unknown command: %1 - -An unknown command has been sent to the stats module. The stats module -will respond with an error and the command will be ignored. - - - - -STATS_SEND_REQUEST_BOSS requesting boss to send statistics - -This debug message is printed when a request is sent to the boss module -to send its data to the stats module. - - - - -STATS_STARTING starting - -The stats module will be now starting. - - - - -STATS_START_ERROR stats module error: %1 - -An internal error occurred while starting the stats module. The stats -module will be now shutting down. - - - - -STATS_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the stats module. The -daemon will now shut down. - - - - -STATS_UNKNOWN_COMMAND_IN_SPEC unknown command in specification file: %1 - -The specification file for the stats module contains a command that -is unknown in the implementation. The most likely cause is an -installation problem, where the specification file stats.spec is -from a different version of BIND 10 than the stats module itself. -Please check your installation. - - - - -XFRIN_AXFR_INCONSISTENT_SOA AXFR SOAs are inconsistent for %1: %2 expected, %3 received - -The serial fields of the first and last SOAs of AXFR (including AXFR-style -IXFR) are not the same. According to RFC 5936 these two SOAs must be the -"same" (not only for the serial), but it is still not clear what the -receiver should do if this condition does not hold. There was a discussion -about this at the IETF dnsext wg: -http://www.ietf.org/mail-archive/web/dnsext/current/msg07908.html -and the general feeling seems that it would be better to reject the -transfer if a mismatch is detected. On the other hand, also as noted -in that email thread, neither BIND 9 nor NSD performs any comparison -on the SOAs. For now, we only check the serials (ignoring other fields) -and only leave a warning log message when a mismatch is found. If it -turns out to happen with a real world primary server implementation -and that server actually feeds broken data (e.g. mixed versions of -zone), we can consider a stricter action. - - - - -XFRIN_BAD_MASTER_ADDR_FORMAT bad format for master address: %1 - -The given master address is not a valid IP address. - - - - -XFRIN_BAD_MASTER_PORT_FORMAT bad format for master port: %1 - -The master port as read from the configuration is not a valid port number. - - - - -XFRIN_BAD_TSIG_KEY_STRING bad TSIG key string: %1 - -The TSIG key string as read from the configuration does not represent -a valid TSIG key. - - - - -XFRIN_BAD_ZONE_CLASS Invalid zone class: %1 - -The zone class as read from the configuration is not a valid DNS class. - - - - -XFRIN_CC_SESSION_ERROR error reading from cc channel: %1 - -There was a problem reading from the command and control channel. The -most likely cause is that xfrin the msgq daemon is not running. - - - - -XFRIN_COMMAND_ERROR error while executing command '%1': %2 - -There was an error while the given command was being processed. The -error is given in the log message. - - - - -XFRIN_CONNECT_MASTER error connecting to master at %1: %2 - -There was an error opening a connection to the master. The error is -shown in the log message. - - - - -XFRIN_GOT_INCREMENTAL_RESP got incremental response for %1 - -In an attempt of IXFR processing, the begenning SOA of the first difference -(following the initial SOA that specified the final SOA for all the -differences) was found. This means a connection for xfrin tried IXFR -and really aot a response for incremental updates. - - - - -XFRIN_GOT_NONINCREMENTAL_RESP got nonincremental response for %1 - -Non incremental transfer was detected at the "first data" of a transfer, -which is the RR following the initial SOA. Non incremental transfer is -either AXFR or AXFR-style IXFR. In the latter case, it means that -in a response to IXFR query the first data is not SOA or its SOA serial -is not equal to the requested SOA serial. - - - - -XFRIN_IMPORT_DNS error importing python DNS module: %1 - -There was an error importing the python DNS module pydnspp. The most -likely cause is a PYTHONPATH problem. - - - - -XFRIN_IXFR_UPTODATE IXFR requested serial for %1 is %2, master has %3, not updating - -The first SOA record in an IXFR response indicates the zone's serial -at the primary server is not newer than the client's. This is -basically unexpected event because normally the client first checks -the SOA serial by an SOA query, but can still happen if the transfer -is manually invoked or (although unlikely) there is a rapid change at -the primary server between the SOA and IXFR queries. The client -implementation confirms the whole response is this single SOA, and -aborts the transfer just like a successful case. - - - - -XFRIN_MSGQ_SEND_ERROR error while contacting %1 and %2 - -There was a problem sending a message to the xfrout module or the -zone manager. This most likely means that the msgq daemon has quit or -was killed. - - - - -XFRIN_MSGQ_SEND_ERROR_ZONE_MANAGER error while contacting %1 - -There was a problem sending a message to the zone manager. This most -likely means that the msgq daemon has quit or was killed. - - - - -XFRIN_NOTIFY_UNKNOWN_MASTER got notification to retransfer zone %1 from %2, expected %3 - -The system received a notify for the given zone, but the address it came -from does not match the master address in the Xfrin configuration. The notify -is ignored. This may indicate that the configuration for the master is wrong, -that a wrong machine is sending notifies, or that fake notifies are being sent. - - - - -XFRIN_RETRANSFER_UNKNOWN_ZONE got notification to retransfer unknown zone %1 - -There was an internal command to retransfer the given zone, but the -zone is not known to the system. This may indicate that the configuration -for xfrin is incomplete, or there was a typographical error in the -zone name in the configuration. - - - - -XFRIN_STARTING starting resolver with command line '%1' - -An informational message, this is output when the resolver starts up. - - - - -XFRIN_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the xfrin daemon. The -daemon will now shut down. - - - - -XFRIN_UNKNOWN_ERROR unknown error: %1 - -An uncaught exception was raised while running the xfrin daemon. The -exception message is printed in the log message. - - - - -XFRIN_XFR_OTHER_FAILURE %1 transfer of zone %2 failed: %3 - -The XFR transfer for the given zone has failed due to a problem outside -of the xfrin module. Possible reasons are a broken DNS message or failure -in database connection. The error is shown in the log message. - - - - -XFRIN_XFR_PROCESS_FAILURE %1 transfer of zone %2/%3 failed: %4 - -An XFR session failed outside the main protocol handling. This -includes an error at the data source level at the initialization -phase, unexpected failure in the network connection setup to the -master server, or even more unexpected failure due to unlikely events -such as memory allocation failure. Details of the error are shown in -the log message. In general, these errors are not really expected -ones, and indicate an installation error or a program bug. The -session handler thread tries to clean up all intermediate resources -even on these errors, but it may be incomplete. So, if this log -message continuously appears, system resource consumption should be -checked, and you may even want to disable the corresponding transfers. -You may also want to file a bug report if this message appears so -often. - - - - -XFRIN_XFR_TRANSFER_FAILURE %1 transfer of zone %2 with %3 failed: %4 - -The XFR transfer for the given zone has failed due to an internal error. -The error is shown in the log message. - - - - -XFRIN_XFR_TRANSFER_FALLBACK falling back from IXFR to AXFR for %1 - -The IXFR transfer of the given zone failed. This might happen in many cases, -such that the remote server doesn't support IXFR, we don't have the SOA record -(or the zone at all), we are out of sync, etc. In many of these situations, -AXFR could still work. Therefore we try that one in case it helps. - - - - -XFRIN_XFR_TRANSFER_PROTOCOL_ERROR %1 transfer of zone %2 with %3 failed: %4 - -The XFR transfer for the given zone has failed due to a protocol -error, such as an unexpected response from the primary server. The -error is shown in the log message. It may be because the primary -server implementation is broken or (although less likely) there was -some attack attempt, but it can also happen due to configuration -mismatch such as the remote server does not have authority for the -zone any more but the local configuration hasn't been updated. So it -is recommended to check the primary server configuration. - - - - -XFRIN_XFR_TRANSFER_STARTED %1 transfer of zone %2 started - -A connection to the master server has been made, the serial value in -the SOA record has been checked, and a zone transfer has been started. - - - - -XFRIN_XFR_TRANSFER_SUCCESS %1 transfer of zone %2 succeeded - -The XFR transfer of the given zone was successfully completed. - - - - -XFRIN_ZONE_CREATED Zone %1 not found in the given data source, newly created - -On starting an xfrin session, it is identified that the zone to be -transferred is not found in the data source. This can happen if a -secondary DNS server first tries to perform AXFR from a primary server -without creating the zone image beforehand (e.g. by b10-loadzone). As -of this writing the xfrin process provides backward compatible -behavior to previous versions: creating a new one in the data source -not to surprise existing users too much. This is probably not a good -idea, however, in terms of who should be responsible for managing -zones at a higher level. In future it is more likely that a separate -zone management framework is provided, and the situation where the -given zone isn't found in xfrout will be treated as an error. - - - - -XFRIN_ZONE_MULTIPLE_SOA Zone %1 has %2 SOA RRs - -On starting an xfrin session, it is identified that the zone to be -transferred has multiple SOA RRs. Such a zone is broken, but could be -accidentally configured especially in a data source using "non -captive" backend database. The implementation ignores entire SOA RRs -and tries to continue processing as if the zone were empty. This -means subsequent AXFR can succeed and possibly replace the zone with -valid content, but an IXFR attempt will fail. - - - - -XFRIN_ZONE_NO_SOA Zone %1 does not have SOA - -On starting an xfrin session, it is identified that the zone to be -transferred does not have an SOA RR in the data source. This is not -necessarily an error; if a secondary DNS server first tries to perform -transfer from a primary server, the zone can be empty, and therefore -doesn't have an SOA. Subsequent AXFR will fill in the zone; if the -attempt is IXFR it will fail in query creation. - - - - -XFRIN_ZONE_SERIAL_AHEAD Serial number (%1) for %2 received from master %3 < ours (%4) - -The response to an SOA query prior to xfr indicated that the zone's -SOA serial at the primary server is smaller than that of the xfrin -client. This is not necessarily an error especially if that -particular primary server is another secondary server which hasn't got -the latest version of the zone. But if the primary server is known to -be the real source of the zone, some unexpected inconsistency may have -happened, and you may want to take a closer look. In this case xfrin -doesn't perform subsequent zone transfer. - - - - -XFROUT_BAD_TSIG_KEY_STRING bad TSIG key string: %1 - -The TSIG key string as read from the configuration does not represent -a valid TSIG key. - - - - -XFROUT_CC_SESSION_ERROR error reading from cc channel: %1 - -There was a problem reading from the command and control channel. The -most likely cause is that the msgq daemon is not running. - - - - -XFROUT_CC_SESSION_TIMEOUT_ERROR timeout waiting for cc response - -There was a problem reading a response from another module over the -command and control channel. The most likely cause is that the -configuration manager b10-cfgmgr is not running. - - - - -XFROUT_CONFIG_ERROR error found in configuration data: %1 - -The xfrout process encountered an error when installing the configuration at -startup time. Details of the error are included in the log message. - - - - -XFROUT_FETCH_REQUEST_ERROR socket error while fetching a request from the auth daemon - -There was a socket error while contacting the b10-auth daemon to -fetch a transfer request. The auth daemon may have shutdown. - - - - -XFROUT_HANDLE_QUERY_ERROR error while handling query: %1 - -There was a general error handling an xfrout query. The error is shown -in the message. In principle this error should not appear, and points -to an oversight catching exceptions in the right place. However, to -ensure the daemon keeps running, this error is caught and reported. - - - - -XFROUT_IMPORT error importing python module: %1 - -There was an error importing a python module. One of the modules needed -by xfrout could not be found. This suggests that either some libraries -are missing on the system, or the PYTHONPATH variable is not correct. -The specific place where this library needs to be depends on your -system and your specific installation. - - - - -XFROUT_IXFR_MULTIPLE_SOA IXFR client %1: authority section has multiple SOAs - -An IXFR request was received with more than one SOA RRs in the authority -section. The xfrout daemon rejects the request with an RCODE of -FORMERR. - - - - -XFROUT_IXFR_NO_JOURNAL_SUPPORT IXFR client %1, %2: journaling not supported in the data source, falling back to AXFR - -An IXFR request was received but the underlying data source did -not support journaling. The xfrout daemon fell back to AXFR-style -IXFR. - - - - -XFROUT_IXFR_NO_SOA IXFR client %1: missing SOA - -An IXFR request was received with no SOA RR in the authority section. -The xfrout daemon rejects the request with an RCODE of FORMERR. - - - - -XFROUT_IXFR_NO_VERSION IXFR client %1, %2: version (%3 to %4) not in journal, falling back to AXFR - -An IXFR request was received, but the requested range of differences -were not found in the data source. The xfrout daemon fell back to -AXFR-style IXFR. - - - - -XFROUT_IXFR_NO_ZONE IXFR client %1, %2: zone not found with journal - -The requested zone in IXFR was not found in the data source -even though the xfrout daemon sucessfully found the SOA RR of the zone -in the data source. This can happen if the administrator removed the -zone from the data source within the small duration between these -operations, but it's more likely to be a bug or broken data source. -Unless you know why this message was logged, and especially if it -happens often, it's advisable to check whether the data source is -valid for this zone. The xfrout daemon considers it a possible, -though unlikely, event, and returns a response with an RCODE of -NOTAUTH. - - - - -XFROUT_IXFR_UPTODATE IXFR client %1, %2: client version is new enough (theirs=%3, ours=%4) - -An IXFR request was received, but the client's SOA version is the same as -or newer than that of the server. The xfrout server responds to the -request with the answer section being just one SOA of that version. -Note: as of this wrting the 'newer version' cannot be identified due to -the lack of support for the serial number arithmetic. This will soon -be implemented. - - - - -XFROUT_MODULECC_SESSION_ERROR error encountered by configuration/command module: %1 - -There was a problem in the lower level module handling configuration and -control commands. This could happen for various reasons, but the most likely -cause is that the configuration database contains a syntax error and xfrout -failed to start at initialization. A detailed error message from the module -will also be displayed. - - - - -XFROUT_NEW_CONFIG Update xfrout configuration - -New configuration settings have been sent from the configuration -manager. The xfrout daemon will now apply them. - - - - -XFROUT_NEW_CONFIG_DONE Update xfrout configuration done - -The xfrout daemon is now done reading the new configuration settings -received from the configuration manager. - - - - -XFROUT_NOTIFY_COMMAND received command to send notifies for %1/%2 - -The xfrout daemon received a command on the command channel that -NOTIFY packets should be sent for the given zone. - - - - -XFROUT_PARSE_QUERY_ERROR error parsing query: %1 - -There was a parse error while reading an incoming query. The parse -error is shown in the log message. A remote client sent a packet we -do not understand or support. The xfrout request will be ignored. -In general, this should only occur for unexpected problems like -memory allocation failures, as the query should already have been -parsed by the b10-auth daemon, before it was passed here. - - - - -XFROUT_PROCESS_REQUEST_ERROR error processing transfer request: %2 - -There was an error processing a transfer request. The error is included -in the log message, but at this point no specific information other -than that could be given. This points to incomplete exception handling -in the code. - - - - -XFROUT_QUERY_DROPPED %1 client %2: request to transfer %3 dropped - -The xfrout process silently dropped a request to transfer zone to -given host. This is required by the ACLs. The %2 represents the IP -address and port of the peer requesting the transfer, and the %3 -represents the zone name and class. - - - - -XFROUT_QUERY_QUOTA_EXCCEEDED %1 client %2: request denied due to quota (%3) - -The xfr request was rejected because the server was already handling -the maximum number of allowable transfers as specified in the transfers_out -configuration parameter, which is also shown in the log message. The -request was immediately responded and terminated with an RCODE of REFUSED. -This can happen for a busy xfrout server, and you may want to increase -this parameter; if the server is being too busy due to requests from -unexpected clients you may want to restrict the legitimate clients -with ACL. - - - - -XFROUT_QUERY_REJECTED %1 client %2: request to transfer %3 rejected - -The xfrout process rejected (by REFUSED rcode) a request to transfer zone to -given host. This is because of ACLs. The %2 represents the IP -address and port of the peer requesting the transfer, and the %3 -represents the zone name and class. - - - - -XFROUT_RECEIVED_SHUTDOWN_COMMAND shutdown command received - -The xfrout daemon received a shutdown command from the command channel -and will now shut down. - - - - -XFROUT_RECEIVE_FILE_DESCRIPTOR_ERROR error receiving the file descriptor for an XFR connection - -There was an error receiving the file descriptor for the transfer -request. Normally, the request is received by b10-auth, and passed on -to the xfrout daemon, so it can answer directly. However, there was a -problem receiving this file descriptor. The request will be ignored. - - - - -XFROUT_REMOVE_OLD_UNIX_SOCKET_FILE_ERROR error removing unix socket file %1: %2 - -The unix socket file xfrout needs for contact with the auth daemon -already exists, and needs to be removed first, but there is a problem -removing it. It is likely that we do not have permission to remove -this file. The specific error is show in the log message. The xfrout -daemon will shut down. - - - - -XFROUT_REMOVE_UNIX_SOCKET_FILE_ERROR error clearing unix socket file %1: %2 - -When shutting down, the xfrout daemon tried to clear the unix socket -file used for communication with the auth daemon. It failed to remove -the file. The reason for the failure is given in the error message. - - - - -XFROUT_SOCKET_SELECT_ERROR error while calling select() on request socket: %1 - -There was an error while calling select() on the socket that informs -the xfrout daemon that a new xfrout request has arrived. This should -be a result of rare local error such as memory allocation failure and -shouldn't happen under normal conditions. The error is included in the -log message. - - - - -XFROUT_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down - -There was a keyboard interrupt signal to stop the xfrout daemon. The -daemon will now shut down. - - - - -XFROUT_STOPPING the xfrout daemon is shutting down - -The current transfer is aborted, as the xfrout daemon is shutting down. - - - - -XFROUT_UNIX_SOCKET_FILE_IN_USE another xfrout process seems to be using the unix socket file %1 - -While starting up, the xfrout daemon tried to clear the unix domain -socket needed for contacting the b10-auth daemon to pass requests -on, but the file is in use. The most likely cause is that another -xfrout daemon process is still running. This xfrout daemon (the one -printing this message) will not start. - - - - -XFROUT_XFR_TRANSFER_CHECK_ERROR %1 client %2: check for transfer of %3 failed: %4 - -Pre-response check for an incomding XFR request failed unexpectedly. -The most likely cause of this is that some low level error in the data -source, but it may also be other general (more unlikely) errors such -as memory shortage. Some detail of the error is also included in the -message. The xfrout server tries to return a SERVFAIL response in this case. - - - - -XFROUT_XFR_TRANSFER_DONE %1 client %2: transfer of %3 complete - -The transfer of the given zone has been completed successfully, or was -aborted due to a shutdown event. - - - - -XFROUT_XFR_TRANSFER_ERROR %1 client %2: error transferring zone %3: %4 - -An uncaught exception was encountered while sending the response to -an AXFR query. The error message of the exception is included in the -log message, but this error most likely points to incomplete exception -handling in the code. - - - - -XFROUT_XFR_TRANSFER_FAILED %1 client %2: transfer of %3 failed, rcode: %4 - -A transfer out for the given zone failed. An error response is sent -to the client. The given rcode is the rcode that is set in the error -response. This is either NOTAUTH (we are not authoritative for the -zone), SERVFAIL (our internal database is missing the SOA record for -the zone), or REFUSED (the limit of simultaneous outgoing AXFR -transfers, as specified by the configuration value -Xfrout/max_transfers_out, has been reached). - - - - -XFROUT_XFR_TRANSFER_STARTED %1 client %2: transfer of zone %3 has started - -A transfer out of the given zone has started. - - - - -ZONEMGR_CCSESSION_ERROR command channel session error: %1 - -An error was encountered on the command channel. The message indicates -the nature of the error. - - - - -ZONEMGR_JITTER_TOO_BIG refresh_jitter is too big, setting to 0.5 - -The value specified in the configuration for the refresh jitter is too large -so its value has been set to the maximum of 0.5. - - - - -ZONEMGR_KEYBOARD_INTERRUPT exiting zonemgr process as result of keyboard interrupt - -An informational message output when the zone manager was being run at a -terminal and it was terminated via a keyboard interrupt signal. - - - - -ZONEMGR_LOAD_ZONE loading zone %1 (class %2) - -This is a debug message indicating that the zone of the specified class -is being loaded. - - - - -ZONEMGR_NO_MASTER_ADDRESS internal BIND 10 command did not contain address of master - -A command received by the zone manager from the Auth module did not -contain the address of the master server from which a NOTIFY message -was received. This may be due to an internal programming error; please -submit a bug report. - - - - -ZONEMGR_NO_SOA zone %1 (class %2) does not have an SOA record - -When loading the named zone of the specified class the zone manager -discovered that the data did not contain an SOA record. The load has -been abandoned. - - - - -ZONEMGR_NO_TIMER_THREAD trying to stop zone timer thread but it is not running - -An attempt was made to stop the timer thread (used to track when zones -should be refreshed) but it was not running. This may indicate an -internal program error. Please submit a bug report. - - - - -ZONEMGR_NO_ZONE_CLASS internal BIND 10 command did not contain class of zone - -A command received by the zone manager from another BIND 10 module did -not contain the class of the zone on which the zone manager should act. -This may be due to an internal programming error; please submit a -bug report. - - - - -ZONEMGR_NO_ZONE_NAME internal BIND 10 command did not contain name of zone - -A command received by the zone manager from another BIND 10 module did -not contain the name of the zone on which the zone manager should act. -This may be due to an internal programming error; please submit a -bug report. - - - - -ZONEMGR_RECEIVE_NOTIFY received NOTIFY command for zone %1 (class %2) - -This is a debug message indicating that the zone manager has received a -NOTIFY command over the command channel. The command is sent by the Auth -process when it is acting as a slave server for the zone and causes the -zone manager to record the master server for the zone and start a timer; -when the timer expires, the master will be polled to see if it contains -new data. - - - - -ZONEMGR_RECEIVE_SHUTDOWN received SHUTDOWN command - -This is a debug message indicating that the zone manager has received -a SHUTDOWN command over the command channel from the Boss process. -It will act on this command and shut down. - - - - -ZONEMGR_RECEIVE_UNKNOWN received unknown command '%1' - -This is a warning message indicating that the zone manager has received -the stated command over the command channel. The command is not known -to the zone manager and although the command is ignored, its receipt -may indicate an internal error. Please submit a bug report. - - - - -ZONEMGR_RECEIVE_XFRIN_FAILED received XFRIN FAILED command for zone %1 (class %2) - -This is a debug message indicating that the zone manager has received -an XFRIN FAILED command over the command channel. The command is sent -by the Xfrin process when a transfer of zone data into the system has -failed, and causes the zone manager to schedule another transfer attempt. - - - - -ZONEMGR_RECEIVE_XFRIN_SUCCESS received XFRIN SUCCESS command for zone %1 (class %2) - -This is a debug message indicating that the zone manager has received -an XFRIN SUCCESS command over the command channel. The command is sent -by the Xfrin process when the transfer of zone data into the system has -succeeded, and causes the data to be loaded and served by BIND 10. - - - - -ZONEMGR_REFRESH_ZONE refreshing zone %1 (class %2) - -The zone manager is refreshing the named zone of the specified class -with updated information. - - - - -ZONEMGR_SELECT_ERROR error with select(): %1 - -An attempt to wait for input from a socket failed. The failing operation -is a call to the operating system's select() function, which failed for -the given reason. - - - - -ZONEMGR_SEND_FAIL failed to send command to %1, session has been closed - -The zone manager attempted to send a command to the named BIND 10 module, -but the send failed. The session between the modules has been closed. - - - - -ZONEMGR_SESSION_ERROR unable to establish session to command channel daemon - -The zonemgr process was not able to be started because it could not -connect to the command channel daemon. The most usual cause of this -problem is that the daemon is not running. - - - - -ZONEMGR_SESSION_TIMEOUT timeout on session to command channel daemon - -The zonemgr process was not able to be started because it timed out when -connecting to the command channel daemon. The most usual cause of this -problem is that the daemon is not running. - - - - -ZONEMGR_SHUTDOWN zone manager has shut down - -A debug message, output when the zone manager has shut down completely. - - - - -ZONEMGR_STARTING zone manager starting - -A debug message output when the zone manager starts up. - - - - -ZONEMGR_TIMER_THREAD_RUNNING trying to start timer thread but one is already running - -This message is issued when an attempt is made to start the timer -thread (which keeps track of when zones need a refresh) but one is -already running. It indicates either an error in the program logic or -a problem with stopping a previous instance of the timer. Please submit -a bug report. - - - - -ZONEMGR_UNKNOWN_ZONE_FAIL zone %1 (class %2) is not known to the zone manager - -An XFRIN operation has failed but the zone that was the subject of the -operation is not being managed by the zone manager. This may indicate -an error in the program (as the operation should not have been initiated -if this were the case). Please submit a bug report. - - - - -ZONEMGR_UNKNOWN_ZONE_NOTIFIED notified zone %1 (class %2) is not known to the zone manager - -A NOTIFY was received but the zone that was the subject of the operation -is not being managed by the zone manager. This may indicate an error -in the program (as the operation should not have been initiated if this -were the case). Please submit a bug report. - - - - -ZONEMGR_UNKNOWN_ZONE_SUCCESS zone %1 (class %2) is not known to the zone manager - -An XFRIN operation has succeeded but the zone received is not being -managed by the zone manager. This may indicate an error in the program -(as the operation should not have been initiated if this were the case). -Please submit a bug report. - - - - - - From 7a48a76d208b0c687074850837e99989700af160 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 16 Feb 2012 10:41:17 -0600 Subject: [PATCH 002/148] [trac1687] remove generated roff man pages Later steps will make sure these are generated for "make dist" to be included in tarball. --- src/bin/auth/b10-auth.8 | 202 ---------------- src/bin/bind10/bind10.8 | 343 --------------------------- src/bin/bindctl/bindctl.1 | 149 ------------ src/bin/cfgmgr/b10-cfgmgr.8 | 81 ------- src/bin/cmdctl/b10-cmdctl.8 | 97 -------- src/bin/ddns/b10-ddns.8 | 102 -------- src/bin/dhcp4/b10-dhcp4.8 | 60 ----- src/bin/dhcp6/b10-dhcp6.8 | 51 ---- src/bin/host/b10-host.1 | 118 --------- src/bin/loadzone/b10-loadzone.8 | 80 ------- src/bin/msgq/b10-msgq.8 | 127 ---------- src/bin/resolver/b10-resolver.8 | 138 ----------- src/bin/stats/b10-stats-httpd.8 | 132 ----------- src/bin/stats/b10-stats.8 | 154 ------------ src/bin/usermgr/b10-cmdctl-usermgr.8 | 74 ------ src/bin/xfrin/b10-xfrin.8 | 161 ------------- src/bin/xfrout/b10-xfrout.8 | 158 ------------ src/bin/zonemgr/b10-zonemgr.8 | 132 ----------- 18 files changed, 2359 deletions(-) delete mode 100644 src/bin/auth/b10-auth.8 delete mode 100644 src/bin/bind10/bind10.8 delete mode 100644 src/bin/bindctl/bindctl.1 delete mode 100644 src/bin/cfgmgr/b10-cfgmgr.8 delete mode 100644 src/bin/cmdctl/b10-cmdctl.8 delete mode 100644 src/bin/ddns/b10-ddns.8 delete mode 100644 src/bin/dhcp4/b10-dhcp4.8 delete mode 100644 src/bin/dhcp6/b10-dhcp6.8 delete mode 100644 src/bin/host/b10-host.1 delete mode 100644 src/bin/loadzone/b10-loadzone.8 delete mode 100644 src/bin/msgq/b10-msgq.8 delete mode 100644 src/bin/resolver/b10-resolver.8 delete mode 100644 src/bin/stats/b10-stats-httpd.8 delete mode 100644 src/bin/stats/b10-stats.8 delete mode 100644 src/bin/usermgr/b10-cmdctl-usermgr.8 delete mode 100644 src/bin/xfrin/b10-xfrin.8 delete mode 100644 src/bin/xfrout/b10-xfrout.8 delete mode 100644 src/bin/zonemgr/b10-zonemgr.8 diff --git a/src/bin/auth/b10-auth.8 b/src/bin/auth/b10-auth.8 deleted file mode 100644 index 56b173235e..0000000000 --- a/src/bin/auth/b10-auth.8 +++ /dev/null @@ -1,202 +0,0 @@ -'\" t -.\" Title: b10-auth -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: December 28, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-AUTH" "8" "December 28, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-auth \- Authoritative DNS server -.SH "SYNOPSIS" -.HP \w'\fBb10\-auth\fR\ 'u -\fBb10\-auth\fR [\fB\-n\fR] [\fB\-v\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-auth\fR -daemon provides the BIND 10 authoritative DNS server\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. -.PP -This daemon communicates with other BIND 10 components over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-auth\fR -will exit\&. -It receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-n\fR -.RS 4 -Do not cache answers in memory\&. The default is to use the cache for faster responses\&. The cache keeps the most recent 30,000 answers (positive and negative) in memory for 30 seconds (instead of querying the data source, such as SQLite3 database, each time)\&. -.RE -.PP -\fB\-v\fR -.RS 4 -Enabled verbose mode\&. This enables diagnostic messages to STDERR\&. -.RE -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP - -\fIdatabase_file\fR -defines the path to the SQLite3 zone file when using the sqlite datasource\&. The default is -/usr/local/var/bind10\-devel/zone\&.sqlite3\&. -.PP - -\fIdatasources\fR -configures data sources\&. The list items include: -\fItype\fR -to optionally choose the data source type (such as -\(lqmemory\(rq); -\fIclass\fR -to optionally select the class (it defaults to -\(lqIN\(rq); and -\fIzones\fR -to define the -\fIfile\fR -path name and the -\fIorigin\fR -(default domain)\&. By default, this is empty\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.sp -In this development version, currently this is only used for the memory data source\&. Only the IN class is supported at this time\&. By default, the memory data source is disabled\&. Also, currently the zone file must be canonical such as generated by \fBnamed\-compilezone \-D\fR\&. -.sp .5v -.RE -.PP - -\fIlisten_on\fR -is a list of addresses and ports for -\fBb10\-auth\fR -to listen on\&. The list items are the -\fIaddress\fR -string and -\fIport\fR -number\&. By default, -\fBb10\-auth\fR -listens on port 53 on the IPv6 (::) and IPv4 (0\&.0\&.0\&.0) wildcard addresses\&. -.PP - -\fIstatistics\-interval\fR -is the timer interval in seconds for -\fBb10\-auth\fR -to share its statistics information to -\fBb10-stats\fR(8)\&. Statistics updates can be disabled by setting this to 0\&. The default is 60\&. -.PP -The configuration commands are: -.PP - -\fBloadzone\fR -tells -\fBb10\-auth\fR -to load or reload a zone file\&. The arguments include: -\fIclass\fR -which optionally defines the class (it defaults to -\(lqIN\(rq); -\fIorigin\fR -is the domain name of the zone; and -\fIdatasrc\fR -optionally defines the type of datasource (it defaults to -\(lqmemory\(rq)\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.sp -In this development version, currently this only supports the IN class and the memory data source\&. -.sp .5v -.RE -.PP - -\fBsendstats\fR -tells -\fBb10\-auth\fR -to send its statistics data to -\fBb10-stats\fR(8) -immediately\&. -.PP - -\fBshutdown\fR -exits -\fBb10\-auth\fR\&. (Note that the BIND 10 boss process will restart this service\&.) -.SH "STATISTICS DATA" -.PP -The statistics data collected by the -\fBb10\-stats\fR -daemon include: -.PP -auth\&.queries\&.tcp -.RS 4 -Total count of queries received by the -\fBb10\-auth\fR -server over TCP since startup\&. -.RE -.PP -auth\&.queries\&.udp -.RS 4 -Total count of queries received by the -\fBb10\-auth\fR -server over UDP since startup\&. -.RE -.SH "FILES" -.PP - -/usr/local/var/bind10\-devel/zone\&.sqlite3 -\(em Location for the SQLite3 zone database when -\fIdatabase_file\fR -configuration is not defined\&. -.SH "SEE ALSO" -.PP - -\fBb10-cfgmgr\fR(8), -\fBb10-loadzone\fR(8), -\fBb10-msgq\fR(8), -\fBb10-stats\fR(8), -\fBb10-zonemgr\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-auth\fR -daemon was first coded in October 2009\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/bind10/bind10.8 b/src/bin/bind10/bind10.8 deleted file mode 100644 index c2e44e7320..0000000000 --- a/src/bin/bind10/bind10.8 +++ /dev/null @@ -1,343 +0,0 @@ -'\" t -.\" Title: bind10 -.\" Author: [see the "AUTHORS" section] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: November 23, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "BIND10" "8" "November 23, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -bind10 \- BIND 10 boss process -.SH "SYNOPSIS" -.HP \w'\fBbind10\fR\ 'u -\fBbind10\fR [\fB\-c\ \fR\fB\fIconfig\-filename\fR\fR] [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-p\ \fR\fB\fIdata_path\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-w\ \fR\fB\fIwait_time\fR\fR] [\fB\-\-cmdctl\-port\fR\ \fIport\fR] [\fB\-\-config\-file\fR\ \fIconfig\-filename\fR] [\fB\-\-data\-path\fR\ \fIdirectory\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-pid\-file\fR\ \fIfilename\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-verbose\fR] [\fB\-\-wait\ \fR\fB\fIwait_time\fR\fR] -.SH "DESCRIPTION" -.PP -The -\fBbind10\fR -daemon starts up other BIND 10 required daemons\&. It handles restarting of exiting programs and also the shutdown of all managed daemons\&. -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-c\fR \fIconfig\-filename\fR, \fB\-\-config\-file\fR \fIconfig\-filename\fR -.RS 4 -The configuration filename to use\&. Can be either absolute or relative to data path\&. In case it is absolute, value of data path is not considered\&. -.sp -Defaults to b10\-config\&.db\&. -.RE -.PP -\fB\-\-cmdctl\-port\fR \fIport\fR -.RS 4 -The -\fBb10\-cmdctl\fR -daemon will listen on this port\&. (See -b10\-cmdctl(8) -for the default\&.) -.RE -.PP -\fB\-p\fR \fIdirectory\fR, \fB\-\-data\-path\fR \fIdirectory\fR -.RS 4 -The path where BIND 10 programs look for various data files\&. Currently only b10\-cfgmgr uses it to locate the configuration file, but the usage might be extended for other programs and other types of files\&. -.RE -.PP -\fB\-m\fR \fIfile\fR, \fB\-\-msgq\-socket\-file\fR \fIfile\fR -.RS 4 -The UNIX domain socket file for the -\fBb10-msgq\fR(8) -daemon to use\&. The default is -/usr/local/var/bind10\-devel/msg_socket\&. -.RE -.PP -\fB\-n\fR, \fB\-\-no\-cache\fR -.RS 4 -Disables the hot\-spot caching used by the -\fBb10-auth\fR(8) -daemon\&. -.RE -.PP -\fB\-u\fR \fIuser\fR, \fB\-\-user\fR \fIname\fR -.RS 4 -The username for -\fBbind10\fR -to run as\&. - -\fBbind10\fR -must be initially ran as the root user to use this option\&. The default is to run as the current user\&. -.RE -.PP -\fB\-\-pid\-file\fR \fIfilename\fR -.RS 4 -If defined, the PID of the -\fBbind10\fR -is stored in this file\&. This is used for testing purposes\&. -.RE -.PP -\fB\-\-pretty\-name \fR\fB\fIname\fR\fR -.RS 4 -The name this process should have in tools like -\fBps\fR -or -\fBtop\fR\&. This is handy if you have multiple versions/installations of -\fBbind10\fR\&. -.RE -.PP -\fB\-v\fR, \fB\-\-verbose\fR -.RS 4 -Display more about what is going on for -\fBbind10\fR -and its child processes\&. -.RE -.PP -\fB\-w\fR \fIwait_time\fR, \fB\-\-wait\fR \fIwait_time\fR -.RS 4 -Sets the amount of time that BIND 10 will wait for the configuration manager (a key component of BIND 10) to initialize itself before abandoning the start up and terminating with an error\&. The wait_time is specified in seconds and has a default value of 10\&. -.RE -.SH "CONFIGURATION AND COMMANDS" -.PP -The configuration provides settings for components for -\fBbind10\fR -to manage under -\fI/Boss/components/\fR\&. The default elements are: -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-auth\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-cmdctl\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/setuid\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-stats\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-stats\-httpd\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-xfrin\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-xfrout\fR -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fI/Boss/components/b10\-zonemgr\fR -.RE -.PP -(Note that the startup of -\fBb10\-sockcreator\fR, -\fBb10\-cfgmgr\fR, and -\fBb10\-msgq\fR -is not configurable\&. It is hardcoded and -\fBbind10\fR -will not run without them\&.) -.PP -These named sets (listed above) contain the following settings: -.PP -\fIaddress\fR -.RS 4 -The name used for communicating to it on the message bus\&. -.RE -.PP -\fIkind\fR -.RS 4 -This defines how required a component is\&. The possible settings for -\fIkind\fR -are: -\fIcore\fR -(system won\'t start if it won\'t start and -\fBbind10\fR -will shutdown if a -\(lqcore\(rq -component crashes), -\fIdispensable\fR -(\fBbind10\fR -will restart failing component), and -\fIneeded\fR -(\fBbind10\fR -will shutdown if component won\'t initially start, but if crashes later, it will attempt to restart)\&. This setting is required\&. -.RE -.PP -\fIpriority\fR -.RS 4 -This is an integer\&. -\fBbind10\fR -will start the components with largest priority numbers first\&. -.RE -.PP -\fIprocess\fR -.RS 4 -This is the filename of the executable to be started\&. If not defined, then -\fBbind10\fR -will use the component name instead\&. -.RE -.PP -\fIspecial\fR -.RS 4 -This defines if the component is started a special way\&. -.RE -.PP -The -\fIBoss\fR -configuration commands are: -.PP - -\fBgetstats\fR -tells -\fBbind10\fR -to send its statistics data to the -\fBb10\-stats\fR -daemon\&. This is an internal command and not exposed to the administrator\&. - -.PP - -\fBping\fR -is used to check the connection with the -\fBbind10\fR -daemon\&. It returns the text -\(lqpong\(rq\&. -.PP - -\fBsendstats\fR -tells -\fBbind10\fR -to send its statistics data to the -\fBb10\-stats\fR -daemon immediately\&. -.PP - -\fBshow_processes\fR -lists the current processes managed by -\fBbind10\fR\&. The output is an array in JSON format containing the process ID and the name for each\&. - - -.PP - -\fBshutdown\fR -tells -\fBbind10\fR -to shutdown the BIND 10 servers\&. It will tell each process it manages to shutdown and, when complete, -\fBbind10\fR -will exit\&. -.SH "STATISTICS DATA" -.PP -The statistics data collected by the -\fBb10\-stats\fR -daemon include: -.PP -bind10\&.boot_time -.RS 4 -The date and time that the -\fBbind10\fR -process started\&. This is represented in ISO 8601 format\&. -.RE -.SH "SEE ALSO" -.PP - -\fBbindctl\fR(1), -\fBb10-auth\fR(8), -\fBb10-cfgmgr\fR(8), -\fBb10-cmdctl\fR(8), -\fBb10-msgq\fR(8), -\fBb10-xfrin\fR(8), -\fBb10-xfrout\fR(8), -\fBb10-zonemgr\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The development of -\fBbind10\fR -was started in October 2009\&. -.SH "AUTHORS" -.PP -The -\fBbind10\fR -daemon was initially designed by Shane Kerr of ISC\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/bindctl/bindctl.1 b/src/bin/bindctl/bindctl.1 deleted file mode 100644 index 97700d6ea2..0000000000 --- a/src/bin/bindctl/bindctl.1 +++ /dev/null @@ -1,149 +0,0 @@ -'\" t -.\" Title: bindctl -.\" Author: [see the "AUTHORS" section] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: December 23, 2010 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "BINDCTL" "1" "December 23, 2010" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -bindctl \- control and configure BIND 10 -.SH "SYNOPSIS" -.HP \w'\fBbindctl\fR\ 'u -\fBbindctl\fR [\fB\-a\ \fR\fB\fIaddress\fR\fR] [\fB\-h\fR] [\fB\-c\ \fR\fB\fIfile\fR\fR] [\fB\-p\ \fR\fB\fInumber\fR\fR] [\fB\-\-address\ \fR\fB\fIaddress\fR\fR] [\fB\-\-help\fR] [\fB\-\-certificate\-chain\ \fR\fB\fIfile\fR\fR] [\fB\-\-csv\-file\-dir\fR\fB\fIfile\fR\fR] [\fB\-\-port\ \fR\fB\fInumber\fR\fR] [\fB\-\-version\fR] -.SH "DESCRIPTION" -.PP -The -\fBbindctl\fR -tool is a user interface to the BIND 10 services\&. The program can be used to control the components and configure the BIND 10 options\&. The options may be specified -via its interactive command interpreter\&. -.PP - -\fBbindctl\fR -communicates over a HTTPS REST\-ful interface provided by -\fBb10-cmdctl\fR(8)\&. The -\fBb10-cfgmgr\fR(8) -daemon stores the configurations and defines the commands\&. -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-a\fR \fIaddress\fR, \fB\-\-address\fR \fIaddress\fR -.RS 4 -The IPv4 or IPv6 address to use to connect to the running -\fBb10-cmdctl\fR(8) -daemon\&. The default is 127\&.0\&.0\&.1\&. -.RE -.PP -\fB\-c\fR \fIfile\fR, \fB\-\-certificate\-chain\fR \fIfile\fR -.RS 4 -The PEM formatted server certificate validation chain file\&. -.RE -.PP -\fB\-\-csv\-file\-dir\fR\fIfile\fR -.RS 4 -The directory name in which the user/password CSV file is stored (see AUTHENTICATION)\&. By default this option doesn\'t have any value, in which case the "\&.bind10" directory under the user\'s home directory will be used\&. -.RE -.PP -\fB\-h\fR, \fB\-\-help\fR -.RS 4 -Display command usage\&. -.RE -.PP -\fB\-p\fR \fInumber\fR, \fB\-\-port\fR \fInumber\fR -.RS 4 -The port number to use to connect to the running -\fBb10-cmdctl\fR(8) -daemon\&. The default is 8080\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -This default port number may change\&. -.sp .5v -.RE -.RE -.PP -\fB\-\-version\fR -.RS 4 -Display the version number and exit\&. -.RE -.SH "AUTHENTICATION" -.PP -The tool will authenticate using a username and password\&. On the first successful login, it will save the details to a comma\-separated\-value (CSV) file which will be used for later uses of -\fBbindctl\fR\&. The file name is -default_user\&.csv -located under the directory specified by the \-\-csv\-file\-dir option\&. -.SH "USAGE" -.PP -The -\fBbindctl\fR -prompt shows -\(lq> \(rq\&. The prompt will also display the location if changed\&. The options are based on the module in use\&. The usage is: -\fBmodule\fR -\fBcommand\fR -\fIparam1 = value1 , \fR\fI\fIparam2 = value2\fR\fR -.PP - -\fBbindctl\fR\'s interactive interface provides command\-line completion and hints\&. Press the Tab key to get a hint for the module, command, and/or parameters\&. -The arrow keys and Emacs\-style editing keys may be used to edit and recall previous lines\&. -.PP -You can use the -\fBhelp\fR -keyword to receive usage assistance for a module or a module\'s command\&. -.PP -The -\fBquit\fR -command is used to exit -\fBbindctl\fR -(and doesn\'t stop the BIND 10 services)\&. -.PP -The following module is available by default: -\fBconfig\fR -for Configuration commands\&. -Additional modules may be available, such as -\fBBoss\fR, -\fBXfrin\fR, and -\fBAuth\fR\&. -.SH "SEE ALSO" -.PP - -\fBb10-auth\fR(8), -\fBb10-cfgmgr\fR(8), -\fBb10-cmdctl\fR(8), -\fBb10-xfrin\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "AUTHORS" -.PP -The -\fBbindctl\fR -tool and library were initially coded by Zhang Likun of CNNIC for the BIND 10 project\&. The initial manual page was written by Jeremy C\&. Reed of ISC\&. -.SH "HISTORY" -.PP -The initial version (with internal name of -\fBBigTool\fR) was started in October 2009\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/cfgmgr/b10-cfgmgr.8 b/src/bin/cfgmgr/b10-cfgmgr.8 deleted file mode 100644 index 719f4c67cb..0000000000 --- a/src/bin/cfgmgr/b10-cfgmgr.8 +++ /dev/null @@ -1,81 +0,0 @@ -'\" t -.\" Title: b10-cfgmgr -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: March 10, 2010 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-CFGMGR" "8" "March 10, 2010" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-cfgmgr \- Configuration manager -.SH "SYNOPSIS" -.HP \w'\fBb10\-cfgmgr\fR\ 'u -\fBb10\-cfgmgr\fR [\fB\-c\fR\fB\fIconfig\-filename\fR\fR] [\fB\-p\fR\fB\fIdata_path\fR\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-cfgmgr\fR -daemon handles all BIND 10 system configuration\&. It provides persistent storage for configuration, and notifies running BIND 10 modules of configuration changes\&. -.PP -The -\fBbindctl\fR -can be used to talk to this configuration manager via a -\fBb10\-cmdctl\fR -connection\&. -.PP -This daemon communicates over a -\fBb10\-msgq\fR -C\-Channel connection\&. If this connection is not established, -\fBb10\-cfgmgr\fR -will exit\&. -.PP -The daemon may be cleanly stopped by sending the SIGTERM signal to the process\&. This shutdown does not notify the subscribers\&. -.PP -When it exits, it saves its current configuration to -/usr/local/var/bind10\-devel/b10\-config\&.db\&. - -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-c\fR\fIconfig\-filename\fR, \fB\-\-config\-filename\fR \fIconfig\-filename\fR -.RS 4 -The configuration database filename to use\&. Can be either absolute or relative to data path\&. -.sp -Defaults to b10\-config\&.db -.RE -.PP -\fB\-p\fR\fIdata\-path\fR, \fB\-\-data\-path\fR \fIdata\-path\fR -.RS 4 -The path where BIND 10 looks for files\&. The configuration file is looked for here, if it is relative\&. If it is absolute, the path is ignored\&. -.RE -.SH "FILES" -.PP -/usr/local/var/bind10\-devel/b10\-config\&.db -\(em Configuration storage file\&. -.SH "SEE ALSO" -.PP - -\fBbind10\fR(8), -\fBmsgq\fR(8)\&. -.SH "HISTORY" -.PP -The -\fBb10\-cfgmgr\fR -daemon and configuration specification were initially designed by Jelte Jansen of ISC\&. Its development began in October 2009\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/cmdctl/b10-cmdctl.8 b/src/bin/cmdctl/b10-cmdctl.8 deleted file mode 100644 index c8c938b910..0000000000 --- a/src/bin/cmdctl/b10-cmdctl.8 +++ /dev/null @@ -1,97 +0,0 @@ -'\" t -.\" Title: b10-cmdctl -.\" Author: [see the "AUTHORS" section] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: March 9, 2010 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-CMDCTL" "8" "March 9, 2010" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-cmdctl \- BIND 10 remote control daemon -.SH "SYNOPSIS" -.HP \w'\fBb10\-cmdctl\fR\ 'u -\fBb10\-cmdctl\fR [\fB\-a\ \fR\fB\fIstring\fR\fR] [\fB\-h\fR] [\fB\-i\ \fR\fB\fInumber\fR\fR] [\fB\-p\ \fR\fB\fInumber\fR\fR] [\fB\-v\fR] [\fB\-\-address\ \fR\fB\fIstring\fR\fR] [\fB\-\-help\fR] [\fB\-\-idle\-timeout\ \fR\fB\fInumber\fR\fR] [\fB\-\-port\ \fR\fB\fInumber\fR\fR] [\fB\-\-verbose\fR] [\fB\-\-version\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-cmdctl\fR -daemon provides an entry for commands sent to the BIND 10 services\&. For example, the -\fBbindctl\fR -user interface communicates via -\fBb10\-cmdctl\fR\&. -.PP -It is a lightweight HTTPS server with HTTP Digest Authentication (username and password validation)\&. It offers a RESTful style interface\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-a \fR\fB\fIstring\fR\fR, \fB\-\-address \fR\fB\fIstring\fR\fR -.RS 4 -The IP address that -\fBb10\-cmdctl\fR -will listen on\&. The default is 127\&.0\&.0\&.1\&. -.RE -.PP -\fB\-h\fR, \fB\-\-help\fR -.RS 4 -Display command usage\&. -.RE -.PP -\fB\-i \fR\fB\fInumber\fR\fR, \fB\-\-idle\-timeout \fR\fB\fInumber\fR\fR -.RS 4 -The socket idle timeout for the HTTPS connection in seconds\&. The default is 1200 seconds\&. -.RE -.PP -\fB\-p \fR\fB\fInumber\fR\fR, \fB\-\-port \fR\fB\fInumber\fR\fR -.RS 4 -The port number -\fBb10\-cmdctl\fR -will listen on\&. The default is 8080\&. -.RE -.PP -\fB\-v\fR, \fB\-\-verbose\fR -.RS 4 -Enable verbose mode\&. -.RE -.PP -\fB\-\-version\fR -.RS 4 -Display the version number and exit\&. -.RE -.SH "FILES" -.PP -/usr/local/etc/bind10\-devel/cmdctl\-accounts\&.csv -\(em account database containing the name, hashed password, and the salt\&. -.PP -/usr/local/etc/bind10\-devel/cmdctl\-keyfile\&.pem -\(em contains the Private key\&. -.PP -/usr/local/etc/bind10\-devel/cmdctl\-certfile\&.pem -\(em contains the Certificate\&. -.SH "SEE ALSO" -.PP - -\fBb10-cfgmgr\fR(8), -\fBbind10\fR(8), -\fBbindctl\fR(1)\&. -.SH "AUTHORS" -.PP -The -\fBb10\-cmdctl\fR -daemon was initially designed and coded by Zhang Likun of CNNIC\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/ddns/b10-ddns.8 b/src/bin/ddns/b10-ddns.8 deleted file mode 100644 index 67a50599b5..0000000000 --- a/src/bin/ddns/b10-ddns.8 +++ /dev/null @@ -1,102 +0,0 @@ -'\" t -.\" Title: b10-ddns -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: December 9, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-DDNS" "8" "December 9, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-ddns \- Dynamic DNS update service -.SH "SYNOPSIS" -.HP \w'\fBb10\-ddns\fR\ 'u -\fBb10\-ddns\fR [\fB\-v\fR | \fB\-\-verbose\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-ddns\fR -daemon provides the BIND 10 Dynamic Update (DDNS) service, as specified in RFC 2136\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. When the -\fBb10\-auth\fR -DNS server receives a DDNS update, -\fBb10\-ddns\fR -updates the zone in the BIND 10 zone data store\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.PP -Currently installed is a dummy component\&. It does not provide any functionality\&. It is a skeleton implementation that will be expanded later\&. -.sp .5v -.RE -.PP -This daemon communicates with BIND 10 over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-ddns\fR -will exit\&. -.PP - -\fBb10\-ddns\fR -receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-v\fR, \fB\-\-verbose\fR -.RS 4 -This value is ignored at this moment, but is provided for compatibility with the bind10 Boss process -.RE -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP - -\fIzones\fR -The zones option is a named set of zones that can be updated with DDNS\&. Each entry has one element called update_acl, which is a list of access control rules that define update permissions\&. By default this is empty; DDNS must be explicitely enabled per zone\&. -.PP -The module commands are: -.PP - -\fBshutdown\fR -Exits -\fBb10\-ddns\fR\&. (Note that the BIND 10 boss process will restart this service\&.) -.SH "SEE ALSO" -.PP - -\fBb10-auth\fR(8), -\fBb10-cfgmgr\fR(8), -\fBb10-msgq\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-ddns\fR -daemon was first implemented in December 2011 for the ISC BIND 10 project\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/dhcp4/b10-dhcp4.8 b/src/bin/dhcp4/b10-dhcp4.8 deleted file mode 100644 index 97bdeb8b73..0000000000 --- a/src/bin/dhcp4/b10-dhcp4.8 +++ /dev/null @@ -1,60 +0,0 @@ -'\" t -.\" Title: b10-dhcp4 -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: October 27, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-DHCP4" "8" "October 27, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-dhcp4 \- DHCPv4 server in BIND 10 architecture -.SH "SYNOPSIS" -.HP \w'\fBb10\-dhcp4\fR\ 'u -\fBb10\-dhcp4\fR [\fB\-v\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-dhcp4\fR -daemon will provide the DHCPv4 server implementation when it becomes functional\&. -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-v\fR -.RS 4 -Enable verbose mode\&. -.RE -.SH "SEE ALSO" -.PP - -\fBbind10\fR(8)\&. -.SH "HISTORY" -.PP -The -\fBb10\-dhcp4\fR -daemon was first coded in November 2011 by Tomek Mrugalski\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/dhcp6/b10-dhcp6.8 b/src/bin/dhcp6/b10-dhcp6.8 deleted file mode 100644 index 1f34a9a2a1..0000000000 --- a/src/bin/dhcp6/b10-dhcp6.8 +++ /dev/null @@ -1,51 +0,0 @@ -'\" t -.\" Title: b10-dhcp6 -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: October 27, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-DHCP6" "8" "October 27, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-dhcp6 \- DHCPv6 server in BIND 10 architecture -.SH "SYNOPSIS" -.HP \w'\fBb10\-dhcp6\fR\ 'u -\fBb10\-dhcp6\fR [\fB\-v\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-dhcp6\fR -daemon will provide the DHCPv6 server implementation when it becomes functional\&. -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-v\fR -.RS 4 -Enable verbose mode\&. -.RE -.SH "SEE ALSO" -.PP - -\fBbind10\fR(8)\&. -.SH "HISTORY" -.PP -The -\fBb10\-dhcp6\fR -daemon was first coded in June 2011 by Tomek Mrugalski\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/host/b10-host.1 b/src/bin/host/b10-host.1 deleted file mode 100644 index 050f6a3185..0000000000 --- a/src/bin/host/b10-host.1 +++ /dev/null @@ -1,118 +0,0 @@ -'\" t -.\" Title: b10-host -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: May 4, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-HOST" "1" "May 4, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-host \- DNS lookup utility -.SH "SYNOPSIS" -.HP \w'\fBb10\-host\fR\ 'u -\fBb10\-host\fR [\fB\-a\fR] [\fB\-c\ \fR\fB\fIclass\fR\fR] [\fB\-d\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-r\fR] [\fB\-t\ \fR\fB\fItype\fR\fR] [\fB\-v\fR] [\fIname\fR] [\fB\fIserver\fR\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-host\fR -utility does DNS lookups\&. Its initial goal is to be a -\fBhost\fR(1) -clone, but also add a few features useful for BIND 10 development testing\&. -.PP -By default, it looks up the A, AAAA, and MX record sets for the -\fIname\fR\&. Optionally, you may select a name server to query against by adding the -\fIserver\fR -argument\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-a\fR -.RS 4 -Enable verbose mode and do a query for type ANY\&. (If the -\fB\-t\fR -option is also set, then the ANY query is not done, but it still uses verbose mode\&.) -.RE -.PP -\fB\-c \fR\fB\fIclass\fR\fR -.RS 4 -Define the class for the query\&. The default is IN (Internet)\&. -.RE -.PP -\fB\-d\fR -.RS 4 -Enable verbose output mode, including elapsed time in milliseconds\&. Verbose mode shows the header, question, answer, authority, and additional sections (if provided)\&. (Same as -\fB\-v\fR\&.) -.RE -.PP -\fB\-p \fR\fB\fIport\fR\fR -.RS 4 -Select an alternative port for the query\&. This may be a number or a service name\&. The default is 53 (domain)\&. This is not a standard feature of -\fBhost\fR(1)\&. -.RE -.PP -\fB\-r\fR -.RS 4 -Disable recursive processing by not setting the Recursion Desired flag in the query\&. -.RE -.PP -\fB\-t \fR\fB\fItype\fR\fR -.RS 4 -Select a specific resource record type for the query\&. By default, it looks up the A, AAAA, and MX record sets\&. -(This overrides the -\fB\-a\fR -option\&.) -.RE -.PP -\fB\-v\fR -.RS 4 -Same as -\fB\-d\fR -option\&. -.RE -.SH "COMPATIBILITY / BUGS" -.PP - -\fBb10\-host\fR -does not do reverse lookups by default yet (by detecting if name is a IPv4 or IPv6 address)\&. -.PP -Unknown -\fB\-c\fR -class or -\fB\-t\fR -type causes -\fBb10\-host\fR -to Abort\&. -.PP -Not all types are supported yet for formatting\&. Not all switches are supported yet\&. -.PP -It doesn\'t use -/etc/resolv\&.conf -at this time\&. The default name server used is 127\&.0\&.0\&.1\&. -.PP - -\fB\-p\fR -is not a standard feature\&. -.SH "HISTORY" -.PP -The C++ version of -\fBb10\-host\fR -was started in October 2009 by Jeremy C\&. Reed of ISC\&. Its usage and output were based on the standard -\fBhost\fR -command\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/loadzone/b10-loadzone.8 b/src/bin/loadzone/b10-loadzone.8 deleted file mode 100644 index d563ff2ed2..0000000000 --- a/src/bin/loadzone/b10-loadzone.8 +++ /dev/null @@ -1,80 +0,0 @@ -'\" t -.\" Title: b10-loadzone -.\" Author: [see the "AUTHORS" section] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: March 8, 2010 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-LOADZONE" "8" "March 8, 2010" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-loadzone \- Load DNS Zone File -.SH "SYNOPSIS" -.HP \w'\fBb10\-loadzone\fR\ 'u -\fBb10\-loadzone\fR [\fB\-d\ \fR\fB\fIdatabase\fR\fR] [\fB\-o\ \fR\fB\fIorigin\fR\fR] [filename] -.SH "DESCRIPTION" -.PP -The -\fBb10\-loadzone\fR -utility loads a RFC 1035 style DNS master zone file and stores it in a BIND 10 ready data source format\&. Master files are text files that contain DNS Resource Records in text form\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.sp -Currently only the SQLITE3 data source is supported\&. -.sp .5v -.RE -.PP -Some control entries (aka directives) are supported\&. $ORIGIN is followed by a domain name, and sets the the origin that will be used for relative domain names in subsequent records\&. $INCLUDE is followed by a filename to load\&. -The previous origin is restored after the file is included\&. -$TTL is followed by a time\-to\-live value which is used by any following records that don\'t specify a TTL\&. -.PP -When re\-loading an existing zone, the prior version is completely removed\&. While the new version of the zone is being loaded, the old version remains accessible to queries\&. After the new version is completely loaded, the old version is swapped out and replaced with the new one in a single operation\&. -.SH "ARGUMENTS" -.PP -\-d \fIdatabase\fR -.RS 4 -Defines the filename for the database\&. The default is -/usr/local/var/bind10\-devel/zone\&.sqlite3\&. -.RE -.PP -\-o \fIorigin\fR -.RS 4 -Defines the default origin for the zone file records\&. -.RE -.SH "FILES" -.PP -.SH "SEE ALSO" -.PP - -\fBb10-auth\fR(8), -\fBbind10\fR(8)\&. -.SH "AUTHORS" -.PP -The -\fBb10\-loadzone\fR -tool was initial written by Evan Hunt of ISC\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/msgq/b10-msgq.8 b/src/bin/msgq/b10-msgq.8 deleted file mode 100644 index 37b52281ce..0000000000 --- a/src/bin/msgq/b10-msgq.8 +++ /dev/null @@ -1,127 +0,0 @@ -'\" t -.\" Title: b10-msgq -.\" Author: [see the "AUTHORS" section] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: August 4, 2010 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-MSGQ" "8" "August 4, 2010" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-msgq \- message routing daemon for the Command Channel -.SH "SYNOPSIS" -.HP \w'\fBb10\-msgq\fR\ 'u -\fBb10\-msgq\fR [\fB\-s\ \fR\fB\fIfile\fR\fR] [\fB\-v\fR] [\fB\-\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-verbose\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-msgq\fR -daemon provides message routing for the Command Channel\&. -.PP -The Command Channel is a message bus and subscription manager\&. Programs may subscribe to certain groups to receive messages for that group\&. Every new connection to -\fBb10\-msgq\fR -is assigned a unique identifier \-\- this is the local name\&. The commands it handles are: -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fBgetlname\fR -\(em receive local name\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fBsend\fR -\(em send a message to defined subscribers\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fBsubscribe\fR -\(em add a subscription\&. This means it is a listener for messages for a specific group\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} - -\fBunsubscribe\fR -\(em remove a subscription\&. -.RE -.sp -.RE -.PP -It listens on 127\&.0\&.0\&.1\&. -.PP -The -\fBb10\-msgq\fR -daemon may be cleanly stopped by sending the SIGTERM signal to the process\&. This shutdown does not notify the subscribers\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-s \fR\fB\fIfile\fR\fR, \fB\-\-socket\-file \fR\fB\fIfile\fR\fR -.RS 4 -The UNIX domain socket file this daemon will use\&. The default is -/usr/local/var/bind10\-devel/msg_socket\&. -.RE -.PP -\fB\-v\fR, \fB\-\-verbose\fR -.RS 4 -Enabled verbose mode\&. This enables diagnostic messages to STDERR\&. Displays more about what -\fBb10\-msgq\fR -is doing\&. -.RE -.SH "SEE ALSO" -.PP - -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "AUTHORS" -.PP -The -\fBb10\-msgq\fR -daemon and Control Channel specification were initially designed by Michael Graff of ISC\&. -.SH "HISTORY" -.PP -The python version was first coded in December 2009\&. The C version with now deprecated wire format was coded in September 2009\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/resolver/b10-resolver.8 b/src/bin/resolver/b10-resolver.8 deleted file mode 100644 index 7a4cb6d1fb..0000000000 --- a/src/bin/resolver/b10-resolver.8 +++ /dev/null @@ -1,138 +0,0 @@ -'\" t -.\" Title: b10-resolver -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: December 28, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-RESOLVER" "8" "December 28, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-resolver \- Recursive DNS server -.SH "SYNOPSIS" -.HP \w'\fBb10\-resolver\fR\ 'u -\fBb10\-resolver\fR [\fB\-v\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-resolver\fR -daemon provides the BIND 10 recursive DNS server\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. -.PP -This daemon communicates with other BIND 10 components over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-resolver\fR -will exit\&. -.PP -It also receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-v\fR -.RS 4 -Enable verbose mode\&. This sets logging to the maximum debugging level\&. -.RE -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP - -\fIforward_addresses\fR -defines the list of addresses and ports that -\fBb10\-resolver\fR -should forward queries to\&. Defining this enables forwarding\&. -.PP - -\fIlisten_on\fR -is a list of addresses and ports for -\fBb10\-resolver\fR -to listen on\&. The list items are the -\fIaddress\fR -string and -\fIport\fR -number\&. The defaults are address ::1 port 53 and address 127\&.0\&.0\&.1 port 53\&. -.PP - - - - - - -\fIquery_acl\fR -is a list of query access control rules\&. The list items are the -\fIaction\fR -string and the -\fIfrom\fR -or -\fIkey\fR -strings\&. The possible actions are ACCEPT, REJECT and DROP\&. The -\fIfrom\fR -is a remote (source) IPv4 or IPv6 address or special keyword\&. The -\fIkey\fR -is a TSIG key name\&. The default configuration accepts queries from 127\&.0\&.0\&.1 and ::1\&. -.PP - -\fIretries\fR -is the number of times to retry (resend query) after a query timeout (\fItimeout_query\fR)\&. The default is 3\&. -.PP - -\fIroot_addresses\fR -is a list of addresses and ports for -\fBb10\-resolver\fR -to use directly as root servers to start resolving\&. The list items are the -\fIaddress\fR -string and -\fIport\fR -number\&. By default, a hardcoded address for l\&.root\-servers\&.net (199\&.7\&.83\&.42 or 2001:500:3::42) is used\&. -.PP - -\fItimeout_client\fR -is the number of milliseconds to wait before timing out the incoming client query\&. If set to \-1, this timeout is disabled\&. The default is 4000\&. After this timeout, a SERVFAIL is sent back to the client asking the question\&. (The lookup may continue after the timeout, but a later answer is not returned for the now\-past query\&.) -.PP - -\fItimeout_lookup\fR -is the number of milliseconds before it stops trying the query\&. If set to \-1, this timeout is disabled\&. The default is 30000\&. -.PP - - -\fItimeout_query\fR -is the number of milliseconds to wait before it retries a query\&. If set to \-1, this timeout is disabled\&. The default is 2000\&. -.PP -The configuration command is: -.PP - -\fBshutdown\fR -exits -\fBb10\-resolver\fR\&. (Note that the BIND 10 boss process will restart this service\&.) -.SH "SEE ALSO" -.PP - -\fBb10-cfgmgr\fR(8), -\fBb10-cmdctl\fR(8), -\fBb10-msgq\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-resolver\fR -daemon was first coded in September 2010\&. The initial implementation only provided forwarding\&. Iteration was introduced in January 2011\&. Caching was implemented in February 2011\&. Access control was introduced in June 2011\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/stats/b10-stats-httpd.8 b/src/bin/stats/b10-stats-httpd.8 deleted file mode 100644 index 1206e1d791..0000000000 --- a/src/bin/stats/b10-stats-httpd.8 +++ /dev/null @@ -1,132 +0,0 @@ -'\" t -.\" Title: b10-stats-httpd -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.76.1 -.\" Date: Mar 8, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-STATS\-HTTPD" "8" "Mar 8, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-stats-httpd \- BIND 10 HTTP server for HTTP/XML interface of statistics -.SH "SYNOPSIS" -.HP \w'\fBb10\-stats\-httpd\fR\ 'u -\fBb10\-stats\-httpd\fR [\fB\-v\fR]| [\fB\-\-verbose\fR] -.SH "DESCRIPTION" -.PP - -\fBb10\-stats\-httpd\fR -is a standalone HTTP server\&. It is intended for HTTP/XML interface for statistics module\&. This server process runs as a process separated from the process of the BIND 10 Stats daemon (\fBb10\-stats\fR)\&. The server is initially executed by the BIND 10 boss process (\fBbind10\fR) and eventually exited by it\&. The server is intended to be server requests by HTTP clients like web browsers and third\-party modules\&. When the server is asked, it requests BIND 10 statistics data or its schema from -\fBb10\-stats\fR, and it sends the data back in Python dictionary format and the server converts it into XML format\&. The server sends it to the HTTP client\&. The server can send three types of document, which are XML (Extensible Markup Language), XSD (XML Schema definition) and XSL (Extensible Stylesheet Language)\&. The XML document is the statistics data of BIND 10, The XSD document is the data schema of it, and The XSL document is the style sheet to be showed for the web browsers\&. There is different URL for each document\&. But please note that you would be redirected to the URL of XML document if you request the URL of the root document\&. For example, you would be redirected to http://127\&.0\&.0\&.1:8000/bind10/statistics/xml if you request http://127\&.0\&.0\&.1:8000/\&. Please see the manual and the spec file of -\fBb10\-stats\fR -for more details about the items of BIND 10 statistics\&. The server uses CC session in communication with -\fBb10\-stats\fR\&. CC session is provided by -\fBb10\-msgq\fR -which is started by -\fBbind10\fR -in advance\&. The server is implemented by HTTP\-server libraries included in Python 3\&. The server obtains the configuration from the config manager (\fBb10\-cfgmgr\fR) in runtime\&. Please see below for more details about this spec file and configuration of the server\&. -.SH "OPTIONS" -.PP -The argument is as follow: -.PP -\fB\-v\fR, \fB\-\-verbose\fR -.RS 4 - -\fBb10\-stats\-httpd\fR -switches to verbose mode and sends verbose messages to STDOUT\&. -.RE -.SH "FILES" -.PP - -/usr/local/share/bind10\-devel/stats\-httpd\&.spec -\(em the spec file of -\fBb10\-stats\-httpd\fR\&. This file contains configurable settings of -\fBb10\-stats\-httpd\fR\&. This setting can be configured in runtime via -bindctl(1)\&. Please see the manual of -bindctl(1) -about how to configure the settings\&. -.PP - -/usr/local/share/bind10\-devel/stats\-httpd\-xml\&.tpl -\(em the template file of XML document\&. -.PP - -/usr/local/share/bind10\-devel/stats\-httpd\-xsd\&.tpl -\(em the template file of XSD document\&. -.PP - -/usr/local/share/bind10\-devel/stats\-httpd\-xsl\&.tpl -\(em the template file of XSL document\&. -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable setting in -stats\-httpd\&.spec -is: -.PP -\fIlisten_on\fR -.RS 4 -a list of pairs of address and port for -\fBb10\-stats\-httpd\fR -to listen HTTP requests on\&. The pair consists of the -\fIaddress\fR -string and -\fIport\fR -number\&. The default setting is the list of address 127\&.0\&.0\&.1 port 8000\&. If the server is started by the default setting being left, for example, the URL for XML document is http://127\&.0\&.0\&.1:8000/bind10/statistics/xml\&. And also IPv6 addresses can be configured and they works in the runtime environment for dual stack\&. You can change the settings through -bindctl(8)\&. -.RE -.PP -The commands in -stats\-httpd\&.spec -are: -.PP -\fBstatus\fR -.RS 4 -shows the status of -\fBb10\-stats\-httpd\fR -with its PID\&. -.RE -.PP -\fBshutdown\fR -.RS 4 -exits the -\fBb10\-stats\-httpd\fR -process\&. (Note that the BIND 10 boss process will restart this service\&.) -.RE -.SH "SEE ALSO" -.PP - -\fBb10-stats\fR(8), -\fBb10-msgq\fR(8), -\fBb10-cfgmgr\fR(8), -\fBbind10\fR(8), -\fBbindctl\fR(1), -BIND 10 Guide\&. -.SH "HISTORY" -.PP - -\fBb10\-stats\-httpd\fR -was designed and implemented by Naoki Kambe of JPRS in Mar 2011\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/stats/b10-stats.8 b/src/bin/stats/b10-stats.8 deleted file mode 100644 index 0204ca10bc..0000000000 --- a/src/bin/stats/b10-stats.8 +++ /dev/null @@ -1,154 +0,0 @@ -'\" t -.\" Title: b10-stats -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: August 11, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-STATS" "8" "August 11, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-stats \- BIND 10 statistics module -.SH "SYNOPSIS" -.HP \w'\fBb10\-stats\fR\ 'u -\fBb10\-stats\fR [\fB\-v\fR] [\fB\-\-verbose\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-stats\fR -is a daemon forked by -\fBbind10\fR\&. Stats module collects statistics data from each module and reports statistics information via -\fBbindctl\fR\&. It communicates by using the Command Channel by -\fBb10\-msgq\fR -with other modules like -\fBbind10\fR, -\fBb10\-auth\fR -and so on\&. It waits for coming data from other modules, then other modules send data to stats module periodically\&. Other modules send stats data to stats module independently from implementation of stats module, so the frequency of sending data may not be constant\&. Stats module collects data and aggregates it\&. -\fBb10\-stats\fR -invokes an internal command for -\fBbind10\fR -after its initial starting because it\'s sure to collect statistics data from -\fBbind10\fR\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-v\fR, \fB\-\-verbose\fR -.RS 4 -This -\fBb10\-stats\fR -switches to verbose mode\&. It sends verbose messages to STDOUT\&. -.RE -.SH "CONFIGURATION AND COMMANDS" -.PP -The -\fBb10\-stats\fR -command does not have any configurable settings\&. -.PP -The configuration commands are: -.PP - - -\fBremove\fR -removes the named statistics name and data\&. -.PP - - -\fBreset\fR -will reset all statistics data to default values except for constant names\&. This may re\-add previously removed statistics names\&. -.PP - -\fBset\fR -.PP - -\fBshow\fR -will send the statistics data in JSON format\&. By default, it outputs all the statistics data it has collected\&. An optional item name may be specified to receive individual output\&. -.PP - -\fBshutdown\fR -will shutdown the -\fBb10\-stats\fR -process\&. (Note that the -\fBbind10\fR -parent may restart it\&.) -.PP - -\fBstatus\fR -simply indicates that the daemon is running\&. -.SH "STATISTICS DATA" -.PP -The -\fBb10\-stats\fR -daemon contains these statistics: -.PP -report_time -.RS 4 -The latest report date and time in ISO 8601 format\&. -.RE -.PP -stats\&.boot_time -.RS 4 -The date and time when this daemon was started in ISO 8601 format\&. This is a constant which can\'t be reset except by restarting -\fBb10\-stats\fR\&. -.RE -.PP -stats\&.last_update_time -.RS 4 -The date and time (in ISO 8601 format) when this daemon last received data from another component\&. -.RE -.PP -stats\&.lname -.RS 4 -This is the name used for the -\fBb10\-msgq\fR -command\-control channel\&. (This is a constant which can\'t be reset except by restarting -\fBb10\-stats\fR\&.) -.RE -.PP -stats\&.start_time -.RS 4 -This is the date and time (in ISO 8601 format) when this daemon started collecting data\&. -.RE -.PP -stats\&.timestamp -.RS 4 -The current date and time represented in seconds since UNIX epoch (1970\-01\-01T0 0:00:00Z) with precision (delimited with a period) up to one hundred thousandth of second\&. -.RE -.PP -See other manual pages for explanations for their statistics that are kept track by -\fBb10\-stats\fR\&. -.SH "FILES" -.PP -/usr/local/share/bind10\-devel/stats\&.spec -\(em This is a spec file for -\fBb10\-stats\fR\&. It contains commands for -\fBb10\-stats\fR\&. They can be invoked via -bindctl(1)\&. -.SH "SEE ALSO" -.PP - -\fBb10-stats-httpd\fR(8), -\fBbind10\fR(8), -\fBbindctl\fR(1), -\fBb10-auth\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-stats\fR -daemon was initially designed and implemented by Naoki Kambe of JPRS in October 2010\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/usermgr/b10-cmdctl-usermgr.8 b/src/bin/usermgr/b10-cmdctl-usermgr.8 deleted file mode 100644 index 874ee8f2c0..0000000000 --- a/src/bin/usermgr/b10-cmdctl-usermgr.8 +++ /dev/null @@ -1,74 +0,0 @@ -'\" t -.\" Title: b10-cmdctl-usermgr -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: March 17, 2010 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-CMDCTL\-USERMGR" "8" "March 17, 2010" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-cmdctl-usermgr \- cmdctl user maintenance tool -.SH "SYNOPSIS" -.HP \w'\fBb10\-cmdctl\-usermgr\fR\ 'u -\fBb10\-cmdctl\-usermgr\fR [\fB\-f\ \fR\fB\fIfilename\fR\fR] [\fB\-h\fR] [\fB\-v\fR] [\fB\-\-file\ \fR\fB\fIfilename\fR\fR] [\fB\-\-help\fR] [\fB\-\-version\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-cmdctl\-usermgr\fR -tool may be used to add accounts with passwords for the -\fBb10-cmdctl\fR(8) -daemon\&. -.PP -By default, the accounts are saved in the -cmdctl\-accounts\&.csv -file in the current directory, unless the -\fB\-\-filename\fR -switch is used\&. The entry is appended to the file\&. -.PP -The tool can\'t remove or replace existing entries\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-h\fR, \fB\-\-help\fR -.RS 4 -Report the usage statement and exit\&. -.RE -.PP -\fB\-f \fR\fB\fIfilename\fR\fR, \fB\-\-file \fR\fB\fIfilename\fR\fR -.RS 4 -Define the filename to append the account to\&. The default is -cmdctl\-accounts\&.csv -in the current directory\&. -.RE -.PP -\fB\-v\fR, \fB\-\-version\fR -.RS 4 -Report the version and exit\&. -.RE -.SH "SEE ALSO" -.PP - -\fBb10-cmdctl\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-cmdctl\-usermgr\fR -tool was implemented in January 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/xfrin/b10-xfrin.8 b/src/bin/xfrin/b10-xfrin.8 deleted file mode 100644 index 056103a1b5..0000000000 --- a/src/bin/xfrin/b10-xfrin.8 +++ /dev/null @@ -1,161 +0,0 @@ -'\" t -.\" Title: b10-xfrin -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: October 12, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-XFRIN" "8" "October 12, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-xfrin \- Incoming DNS zone transfer service -.SH "SYNOPSIS" -.HP \w'\fBb10\-xfrin\fR\ 'u -\fBb10\-xfrin\fR -.SH "DESCRIPTION" -.PP -The -\fBb10\-xfrin\fR -daemon provides the BIND 10 incoming DNS zone transfer service\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. When triggered it can request and receive a zone transfer and store the zone in a BIND 10 zone data source\&. -.PP -The -\fBb10\-xfrin\fR -daemon supports both AXFR and IXFR\&. Due to some implementation limitations of the current development release, however, it only tries AXFR by default, and care should be taken to enable IXFR\&. See the BIND 10 Guide for more details\&. -.PP -This daemon communicates with BIND 10 over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-xfrin\fR -will exit\&. -.PP - -\fBb10\-xfrin\fR -receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP -\fItransfers_in\fR -defines the maximum number of inbound zone transfers that can run concurrently\&. The default is 10\&. -.PP - -\fIzones\fR -is a list of zones known to the -\fBb10\-xfrin\fR -daemon\&. The list items are: -\fIname\fR -(the zone name), -\fIclass\fR -(defaults to -\(lqIN\(rq), -\fImaster_addr\fR -(the zone master to transfer from), -\fImaster_port\fR -(defaults to 53), -\fIuse_ixfr\fR -(defaults to false), and -\fItsig_key\fR -(optional TSIG key to use)\&. The -\fItsig_key\fR -is specified using a full string colon\-delimited name:key:algorithm representation (e\&.g\&. -\(lqfoo\&.example\&.org:EvABsfU2h7uofnmqaRCrhHunGsd=:hmac\-sha1\(rq)\&. -.PP -(The site\-wide -\fImaster_addr\fR -and -\fImaster_port\fR -configurations are deprecated; use the -\fIzones\fR -list configuration instead\&.) -.PP -The configuration commands are: -.PP - -\fBnotify\fR -is sent by -\fBb10-zonemgr\fR(8) -when a DNS NOTIFY message is received to initiate a zone transfer\&. -This is an internal command and not exposed to the administrator\&. -.PP - -\fBrefresh\fR -triggers the transfer in for a single zone\&. It is the same as -\fBretransfer\fR -except it checks the SOA serial first\&. -This is an internal command and not exposed to the administrator\&. - -.PP - -\fBrefresh_from_zonemgr\fR -is sent by -\fBb10-zonemgr\fR(8) -according to the SOA\'s REFRESH time to tell -\fBb10\-xfrin\fR -that the zone needs to do a zone refresh\&. This is an internal command and not exposed to the administrator\&. -.PP - -\fBretransfer\fR -triggers the transfer in for a single zone without checking the zone\'s serial number\&. It has the following arguments: -\fIzone_name\fR -to define the zone to request, -\fIzone_class\fR -to define the class (defaults to -\(lqIN\(rq), -\fImaster\fR -to define the IP address of the authoritative server to transfer from, and -\fIport\fR -to define the port number on the authoritative server (defaults to 53)\&. If the address or port is not specified, it will use the value previously defined in the -\fIzones\fR -configuration\&. -.PP - -\fBshutdown\fR -stops all incoming zone transfers and exits -\fBb10\-xfrin\fR\&. (Note that the BIND 10 boss process will restart this service\&.) -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.PP -This prototype version uses SQLite3 as its data source backend\&. Future versions will be configurable, supporting multiple data storage types\&. -.sp .5v -.RE -.SH "SEE ALSO" -.PP - -\fBb10-cfgmgr\fR(8), -\fBb10-msgq\fR(8), -\fBb10-zonemgr\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-xfrin\fR -daemon was implemented in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010-2011 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/xfrout/b10-xfrout.8 b/src/bin/xfrout/b10-xfrout.8 deleted file mode 100644 index c37198c2c6..0000000000 --- a/src/bin/xfrout/b10-xfrout.8 +++ /dev/null @@ -1,158 +0,0 @@ -'\" t -.\" Title: b10-xfrout -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: December 15, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-XFROUT" "8" "December 15, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-xfrout \- Outbound DNS zone transfer service -.SH "SYNOPSIS" -.HP \w'\fBb10\-xfrout\fR\ 'u -\fBb10\-xfrout\fR [\fB\-v\fR] [\fB\-\-verbose\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-xfrout\fR -daemon provides the BIND 10 outgoing DNS zone transfer service using AXFR or IXFR\&. It is also used to send outgoing NOTIFY messages\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. When the -\fBb10\-auth\fR -DNS server receives a transfer request, -\fBb10\-xfrout\fR -sends the zone as found in the BIND 10 zone data store\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.sp -Currently IXFR only works if it gets the zone via \fBb10\-xfrin\fR and only on TCP\&. -.sp .5v -.RE -.PP -This daemon communicates with BIND 10 over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-xfrout\fR -will exit\&. -.PP - -\fBb10\-xfrout\fR -receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP - -\fItransfers_out\fR -defines the maximum number of outgoing zone transfers that can run concurrently\&. The default is 10\&. -.PP - -\fItsig_key_ring\fR -A list of TSIG keys (each of which is in the form of -\fIname:base64\-key[:algorithm]\fR) used for access control on transfer requests\&. The default is an empty list\&. -.PP - -\fItransfer_acl\fR -A list of ACL elements that apply to all transfer requests by default (unless overridden in -\fIzone_config\fR)\&. See the -BIND 10 Guide -for configuration examples\&. The default is an element that allows any transfer requests\&. -.PP - -\fIzone_config\fR -A list of JSON objects (i\&.e\&. maps) that define per zone configuration concerning -\fBb10\-xfrout\fR\&. The supported names of each object are "origin" (the origin name of the zone), "class" (the RR class of the zone, optional, default to "IN"), and "transfer_acl" (ACL only applicable to transfer requests for that zone)\&. See the -BIND 10 Guide -for configuration examples\&. The default is an empty list, that is, no zone specific configuration\&. -.PP - -\fIlog_name\fR -.PP - -\fIlog_file\fR -The location of the log file if using a file channel\&. If undefined, then the file channel is closed\&. The default is -/usr/local/var/bind10\-devel/log/Xfrout\&.log\&. -.PP - -\fIlog_severity\fR -The default is "debug"\&. -.PP - -\fIlog_versions\fR -The default is 5\&. -.PP - -\fIlog_max_bytes\fR -The default is 1048576\&. -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.sp -This prototype version uses SQLite3 as its data source backend\&. Future versions will be configurable, supporting multiple data storage types\&. -.sp .5v -.RE -.PP -The configuration commands are: -.PP - -\fBshutdown\fR -stops all outbound zone transfers and exits -\fBb10\-xfrout\fR\&. (Note that the BIND 10 boss process will restart this service\&.) -.PP - -\fBzone_new_data_ready\fR -is sent from -\fBb10-xfrin\fR(8) -to indicate that the zone transferred in successfully\&. This triggers -\fBb10\-xfrout\fR -to send NOTIFY message(s)\&. This is an internal command and not exposed to the administrator\&. -.SH "SEE ALSO" -.PP - -\fBb10-auth\fR(8), -\fBb10-cfgmgr\fR(8), -\fBb10-msgq\fR(8), -\fBb10-xfrin\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-xfrout\fR -daemon was first implemented in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/zonemgr/b10-zonemgr.8 b/src/bin/zonemgr/b10-zonemgr.8 deleted file mode 100644 index 1d24bbff00..0000000000 --- a/src/bin/zonemgr/b10-zonemgr.8 +++ /dev/null @@ -1,132 +0,0 @@ -'\" t -.\" Title: b10-zonemgr -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: December 8, 2011 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-ZONEMGR" "8" "December 8, 2011" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-zonemgr \- BIND 10 Secondary zone manager -.SH "SYNOPSIS" -.HP \w'\fBb10\-zonemgr\fR\ 'u -\fBb10\-zonemgr\fR [\fB\-v\fR] [\fB\-\-verbose\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-zonemgr\fR -daemon, also known as the BIND 10 secondary manager, keeps track of timers and other information necessary for BIND 10 to act as a DNS slave\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. -.PP -This daemon communicates with BIND 10 over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-zonemgr\fR -will exit\&. -.PP - -\fBb10\-zonemgr\fR -receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP - -\fIlowerbound_refresh\fR -defines the minimum SOA REFRESH time in seconds\&. The default is 10\&. -.PP - -\fIlowerbound_retry\fR -defines the minimum SOA RETRY time in seconds\&. The default is 5\&. -.PP - -\fIrefresh_jitter\fR -is used to provide a time range for randomizing the refresh and retry timers to help avoid many zones needing to do a refresh or retry at the same time\&. This value is a real number\&. The maximum amount is 0\&.5 (the new timer will be within half the original time)\&. The default is 0\&.25 (up to a quarter sooner)\&. Set to 0 to disable this jitter\&. -.PP - -\fIreload_jitter\fR - -This value is a real number\&. The default is 0\&.75\&. -.PP - -\fImax_transfer_timeout\fR -defines the maximum amount of time in seconds for a transfer\&. -The default is 14400 (4 hours)\&. -.PP - -\fIsecondary_zones\fR -is a list of slave zones that the -\fBb10\-zonemgr\fR -should keep timers for\&. The list items include the -\fIname\fR -(which defines the zone name) and the -\fIclass\fR -(which defaults to -\(lqIN\(rq)\&. -.PP -(A deprecated configuration is -\fIjitter_scope\fR -which is superceded by -\fIrefresh_jitter\fR -and -\fIreload_jitter\fR\&.) -.PP -The configuration commands are: -.PP - -\fBnotify\fR -(sent by -\fBb10-auth\fR(8)) tells -\fBb10\-zonemgr\fR -the zone name and class, and the IP address for the master (source of the NOTIFY message)\&. This will set the zone\'s refresh time to now\&. -This is an internal command and not exposed to the administrator\&. -.PP - -\fBshutdown\fR -exits -\fBb10\-zonemgr\fR\&. (Note that the BIND 10 boss process will restart this service\&.) -.PP - -\fBzone_new_data_ready\fR -is sent from -\fBb10-xfrin\fR(8) -to indicate that the zone transferred in successfully\&. This is an internal command and not exposed to the administrator\&. -.PP - -\fBzone_xfrin_failed\fR -is sent from -\fBb10-xfrin\fR(8) -to indicate a failure (such as a transfer\-in was incomplete)\&. The refresh timer for the zone is reset\&. -This is an internal command and not exposed to the administrator\&. -.SH "SEE ALSO" -.PP - -\fBb10-auth\fR(8), -\fBb10-cfgmgr\fR(8), -\fBb10-msgq\fR(8), -\fBb10-xfrin\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-zonemgr\fR -daemon was designed in July 2010 by CNNIC for the ISC BIND 10 project\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010-2011 Internet Systems Consortium, Inc. ("ISC") -.br From bb8fad9e731441f20b07e2e6038a210c63947351 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 16 Feb 2012 14:26:43 -0600 Subject: [PATCH 003/148] [trac1687][master] make --disable-man work This was broken due to misuse of setting. (--disable-man caused it to be enabled still.) This may be changed in trac1687 branch to have different default behavior. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8889ddc984..de7955196a 100644 --- a/configure.ac +++ b/configure.ac @@ -907,7 +907,7 @@ AC_PATH_PROGS(AWK, gawk awk) AC_SUBST(AWK) AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man], - [regenerate man pages [default=no]])], enable_man=yes, enable_man=no) + [regenerate man pages [default=no]])], enable_man=$enableval, enable_man=no) AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno) From c0421ae8e869666361a4b4b05bd888ce8ba1eee1 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 22 Feb 2012 08:25:57 -0600 Subject: [PATCH 004/148] [trac1687][master] include the docbook xml files for the dhcp man pages in the dist tarball --- src/bin/dhcp4/Makefile.am | 2 +- src/bin/dhcp6/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index 513ae1cca2..6c52c05e5c 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -15,7 +15,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp4.8 -EXTRA_DIST = $(man_MANS) dhcp4.spec +EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec if ENABLE_MAN diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index b1b079845c..abfffb9966 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -17,7 +17,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = *.gcno *.gcda spec_config.h man_MANS = b10-dhcp6.8 -EXTRA_DIST = $(man_MANS) dhcp6.spec interfaces.txt +EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec interfaces.txt if ENABLE_MAN From 042efddd3808f82221affe41249159cbeb7efb76 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 22 Feb 2012 10:08:55 -0600 Subject: [PATCH 005/148] [trac1687] fix typo --- doc/guide/bind10-guide.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index eafbbd8c78..751f113cbf 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -915,7 +915,7 @@ address, but the usual ones don't." mean? --> It is possible to start some components multiple times (currently - b10-auth and b10-resolzer). + b10-auth and b10-resolver). You might want to do that to gain more performance (each one uses only single core). Just put multiple entries under different names, like this, with the same config: From 983db587664d12c7d75e5b01af0c97899c1534e9 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 29 Feb 2012 10:29:47 -0600 Subject: [PATCH 006/148] [trac1687] include system_messages.py in tarball --- Makefile.am | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index cc91a564eb..5c6d0bf9a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -89,8 +89,12 @@ systest: cd tests/system; \ sh $(abs_srcdir)/tests/system/runall.sh +### include tool to generate documentation from log message specifications +### in the distributed tarball: +EXTRA_DIST = tools/system_messages.py + #### include external sources in the distributed tarball: -EXTRA_DIST = ext/asio/README +EXTRA_DIST += ext/asio/README EXTRA_DIST += ext/asio/README EXTRA_DIST += ext/asio/asio.hpp EXTRA_DIST += ext/asio/asio/basic_socket.hpp From 682df53277cfb545a1ba34a3a2198cb555cca6f5 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 29 Feb 2012 10:30:10 -0600 Subject: [PATCH 007/148] [trac1687] make man page generation on by default and change help to say how to disable it. Not sure if want to do this or not. The plan in for tarballs to include generated man pages anyways, so maybe this default is not needed. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index de7955196a..3c9666d9db 100644 --- a/configure.ac +++ b/configure.ac @@ -906,8 +906,8 @@ AC_SUBST(PERL) AC_PATH_PROGS(AWK, gawk awk) AC_SUBST(AWK) -AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man], - [regenerate man pages [default=no]])], enable_man=$enableval, enable_man=no) +AC_ARG_ENABLE(man, [AC_HELP_STRING([--disable-man], + [don't generate documentation])], enable_man=$enableval, enable_man=yes) AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno) From 944da84035e466b1b0bdad4703ec0b76cad1e58a Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 29 Feb 2012 10:31:42 -0600 Subject: [PATCH 008/148] [trac1687] reorganize be sure clean removes generated docs fix so works in builddir get rid of regenarate every time for bind10-messages. TODO: need to list all .mes dependencies now since no portable way. --- doc/guide/Makefile.am | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index ffe89c9437..f46f4a95c4 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -1,12 +1,16 @@ -EXTRA_DIST = bind10-guide.css -EXTRA_DIST += bind10-guide.xml bind10-guide.html bind10-guide.txt -EXTRA_DIST += bind10-messages.xml bind10-messages.html +# generated documentation +DOCS = bind10-messages.html bind10-guide.html bind10-guide.txt + +docdir = $(pkgdatadir)/doc/$(PACKAGE) +doc_DATA = $(DOCS) bind10-guide.css + +# TODO: okay to include the generated bind10-messages.xml in dist tarfile too? +EXTRA_DIST = bind10-guide.xml bind10-messages.xml $(doc_DATA) +CLEANFILES = $(DOCS) bind10-messages.xml # This is not a "man" manual, but reuse this for now for docbook. if ENABLE_MAN -.PHONY: bind10-messages.xml - bind10-guide.html: bind10-guide.xml xsltproc --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ @@ -20,7 +24,7 @@ bind10-guide.html: bind10-guide.xml HTML2TXT = elinks -dump -no-numbering -no-references bind10-guide.txt: bind10-guide.html - $(HTML2TXT) $(srcdir)/bind10-guide.html > $@ + $(HTML2TXT) bind10-guide.html > $@ bind10-messages.html: bind10-messages.xml xsltproc --novalid --xinclude --nonet \ @@ -28,9 +32,8 @@ bind10-messages.html: bind10-messages.xml -o $@ \ --stringparam html.stylesheet $(srcdir)/bind10-guide.css \ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \ - $(srcdir)/bind10-messages.xml + bind10-messages.xml -# So many dependencies that it's easiest just to regenerate it every time bind10-messages.xml: $(PYTHON) $(top_srcdir)/tools/system_messages.py -o $@ $(top_srcdir) From 334f4a48f98725bb7775e2b213ef17c99367606e Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Mon, 21 May 2012 13:18:06 -0500 Subject: [PATCH 009/148] [trac1687] all makefile wrapped in ENABLE_MAN In this branch this is enabled by default. --- doc/guide/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index f46f4a95c4..c46ae0da1f 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -1,3 +1,6 @@ +# This is not a "man" manual, but reuse this for now for docbook. +if ENABLE_MAN + # generated documentation DOCS = bind10-messages.html bind10-guide.html bind10-guide.txt @@ -8,9 +11,6 @@ doc_DATA = $(DOCS) bind10-guide.css EXTRA_DIST = bind10-guide.xml bind10-messages.xml $(doc_DATA) CLEANFILES = $(DOCS) bind10-messages.xml -# This is not a "man" manual, but reuse this for now for docbook. -if ENABLE_MAN - bind10-guide.html: bind10-guide.xml xsltproc --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ From 85aa56426b5379cea2de268c48612a7c287bdae8 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Tue, 22 May 2012 15:37:54 -0500 Subject: [PATCH 010/148] [trac1687] add a space -- just a test of new git server --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 3f6892395e..4f2516de95 100644 --- a/README +++ b/README @@ -62,6 +62,6 @@ doc/guide/bind10-guide.txt. For operating system specific tips see the wiki at: - http://bind10.isc.org/wiki/SystemSpecificNotes + http://bind10.isc.org/wiki/SystemSpecificNotes Please see the wiki and the doc/ directory for various documentation. From bf8328d7f90a94ef512b3b0d9de517650bef1a07 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 23 May 2012 07:08:52 -0500 Subject: [PATCH 011/148] [trac1687] reverse prveious change was only for git testing --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 4f2516de95..3f6892395e 100644 --- a/README +++ b/README @@ -62,6 +62,6 @@ doc/guide/bind10-guide.txt. For operating system specific tips see the wiki at: - http://bind10.isc.org/wiki/SystemSpecificNotes + http://bind10.isc.org/wiki/SystemSpecificNotes Please see the wiki and the doc/ directory for various documentation. From ea903ad8903d356528b183bde0d25980a75898d8 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 31 May 2012 14:16:08 -0500 Subject: [PATCH 012/148] [trac1687] remove two more docs from repo --- src/bin/dbutil/b10-dbutil.8 | 92 --------------------- src/bin/resolver/b10-resolver.8 | 140 -------------------------------- 2 files changed, 232 deletions(-) delete mode 100644 src/bin/dbutil/b10-dbutil.8 delete mode 100644 src/bin/resolver/b10-resolver.8 diff --git a/src/bin/dbutil/b10-dbutil.8 b/src/bin/dbutil/b10-dbutil.8 deleted file mode 100644 index 437a69d1ec..0000000000 --- a/src/bin/dbutil/b10-dbutil.8 +++ /dev/null @@ -1,92 +0,0 @@ -'\" t -.\" Title: b10-dbutil -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: March 20, 2012 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-DBUTIL" "8" "March 20, 2012" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-dbutil \- Zone Database Maintenance Utility -.SH "SYNOPSIS" -.HP \w'\fBb10\-dbutil\ \-\-check\fR\ 'u -\fBb10\-dbutil \-\-check\fR [\-\-verbose] [\-\-quiet] [\fIdbfile\fR] -.HP \w'\fBb10\-dbutil\ \-\-upgrade\fR\ 'u -\fBb10\-dbutil \-\-upgrade\fR [\-\-noconfirm] [\-\-verbose] [\-\-quiet] [\fIdbfile\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-dbutil\fR -utility is a general administration utility for SQL databases\&. (Currently only SQLite is supported by BIND 10\&.) It can report the current verion of the schema, and upgrade an existing database to the latest version of the schema\&. -.PP - -\fBb10\-dbutil\fR -operates in one of two modes, check mode or upgrade mode\&. -.PP -In check mode (\fBb10\-dbutil \-\-check\fR), the utility reads the version of the database schema from the database and prints it\&. It will tell you whether the schema is at the latest version supported by BIND 10\&. Exit status is 0 if the schema is at the correct version, 1 if the schema is at an older version, 2 if the schema is at a version not yet supported by this version of b10\-dbutil\&. Any higher value indicates an error during command\-line parsing or execution\&. -.PP -When the upgrade function is selected (\fBb10\-dbutil \-\-upgrade\fR), the utility takes a copy of the database, then upgrades it to the latest version of the schema\&. The contents of the database remain intact\&. (The backup file is a file in the same directory as the database file\&. It has the same name, with "\&.backup" appended to it\&. If a file of that name already exists, the file will have the suffix "\&.backup\-1"\&. If that exists, the file will be suffixed "\&.backup\-2", and so on)\&. Exit status is 0 if the upgrade is either succesful or aborted by the user, and non\-zero if there is an error\&. -.PP -When upgrading the database, it is -\fIstrongly\fR -recommended that BIND 10 not be running while the upgrade is in progress\&. -.SH "ARGUMENTS" -.PP -The arguments are as follows: -.PP -\fB\-\-check\fR -.RS 4 -Selects the version check function, which reports the current version of the database\&. This is incompatible with the \-\-upgrade option\&. -.RE -.PP -\fB\-\-noconfirm\fR -.RS 4 -Only valid with \-\-upgrade, this disables the prompt\&. Normally the utility will print a warning that an upgrade is about to take place and request that you type "Yes" to continue\&. If this switch is given on the command line, no prompt will be issued: the utility will just perform the upgrade\&. -.RE -.PP -\fB\-\-upgrade\fR -.RS 4 -Selects the upgrade function, which upgrades the database to the latest version of the schema\&. This is incompatible with the \-\-upgrade option\&. -.sp -The upgrade function will upgrade a BIND 10 database \- no matter how old the schema \- preserving all data\&. A backup file is created before the upgrade (with the same name as the database, but with "\&.backup" suffixed to it)\&. If the upgrade fails, this file can be copied back to restore the original database\&. -.RE -.PP -\fB\-\-verbose\fR -.RS 4 -Enable verbose mode\&. Each SQL command issued by the utility will be printed to stderr before it is executed\&. -.RE -.PP -\fB\-\-quiet\fR -.RS 4 -Enable quiet mode\&. No output is printed, except errors during command\-line argument parsing, or the user confirmation dialog\&. -.RE -.PP -\fB\fIdbfile\fR\fR -.RS 4 -Name of the database file to check of upgrade\&. -.RE -.SH "COPYRIGHT" -.br -Copyright \(co 2012 Internet Systems Consortium, Inc. ("ISC") -.br diff --git a/src/bin/resolver/b10-resolver.8 b/src/bin/resolver/b10-resolver.8 deleted file mode 100644 index eed69b8547..0000000000 --- a/src/bin/resolver/b10-resolver.8 +++ /dev/null @@ -1,140 +0,0 @@ -'\" t -.\" Title: b10-resolver -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: February 28, 2012 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-RESOLVER" "8" "February 28, 2012" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-resolver \- Recursive DNS server -.SH "SYNOPSIS" -.HP \w'\fBb10\-resolver\fR\ 'u -\fBb10\-resolver\fR [\fB\-v\fR] -.SH "DESCRIPTION" -.PP -The -\fBb10\-resolver\fR -daemon provides the BIND 10 recursive DNS server\&. Normally it is started by the -\fBbind10\fR(8) -boss process\&. -.PP -This daemon communicates with other BIND 10 components over a -\fBb10-msgq\fR(8) -C\-Channel connection\&. If this connection is not established, -\fBb10\-resolver\fR -will exit\&. -.PP -It also receives its configurations from -\fBb10-cfgmgr\fR(8)\&. -.SH "OPTIONS" -.PP -The arguments are as follows: -.PP -\fB\-v\fR -.RS 4 -Enable verbose mode\&. This sets logging to the maximum debugging level\&. -.RE -.SH "CONFIGURATION AND COMMANDS" -.PP -The configurable settings are: -.PP - -\fIforward_addresses\fR -defines the list of addresses and ports that -\fBb10\-resolver\fR -should forward queries to\&. Defining this enables forwarding\&. -.PP - -\fIlisten_on\fR -is a list of addresses and ports for -\fBb10\-resolver\fR -to listen on\&. The list items are the -\fIaddress\fR -string and -\fIport\fR -number\&. The defaults are address ::1 port 53 and address 127\&.0\&.0\&.1 port 53\&. -.PP - - - - - - -\fIquery_acl\fR -is a list of query access control rules\&. The list items are the -\fIaction\fR -string and the -\fIfrom\fR -or -\fIkey\fR -strings\&. The possible actions are ACCEPT, REJECT and DROP\&. The -\fIfrom\fR -is a remote (source) IPv4 or IPv6 address or special keyword\&. The -\fIkey\fR -is a TSIG key name\&. The default configuration accepts queries from 127\&.0\&.0\&.1 and ::1\&. -.PP - -\fIretries\fR -is the number of times to retry (resend query) after a query timeout (\fItimeout_query\fR)\&. The default is 3\&. -.PP - -\fIroot_addresses\fR -is a list of addresses and ports for -\fBb10\-resolver\fR -to use directly as root servers to start resolving\&. The list items are the -\fIaddress\fR -string and -\fIport\fR -number\&. By default, a hardcoded address for l\&.root\-servers\&.net (199\&.7\&.83\&.42 or 2001:500:3::42) is used\&. -.PP - -\fItimeout_client\fR -is the number of milliseconds to wait before timing out the incoming client query\&. If set to \-1, this timeout is disabled\&. The default is 4000\&. After this timeout, a SERVFAIL is sent back to the client asking the question\&. (The lookup may continue after the timeout, but a later answer is not returned for the now\-past query\&.) -.PP - -\fItimeout_lookup\fR -is the number of milliseconds before it stops trying the query\&. If set to \-1, this timeout is disabled\&. The default is 30000\&. -.PP - - -\fItimeout_query\fR -is the number of milliseconds to wait before it retries a query\&. If set to \-1, this timeout is disabled\&. The default is 2000\&. -.PP -The configuration command is: -.PP - -\fBshutdown\fR -exits -\fBb10\-resolver\fR\&. This has an optional -\fIpid\fR -argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.) -.SH "SEE ALSO" -.PP - -\fBb10-cfgmgr\fR(8), -\fBb10-cmdctl\fR(8), -\fBb10-msgq\fR(8), -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-resolver\fR -daemon was first coded in September 2010\&. The initial implementation only provided forwarding\&. Iteration was introduced in January 2011\&. Caching was implemented in February 2011\&. Access control was introduced in June 2011\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC") -.br From e6cccc208317b2c175f28bc8fee16fe4e4d12c79 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 31 May 2012 14:16:46 -0500 Subject: [PATCH 013/148] [trac1687] don't redefine docdir It was wrong anyways. Just use what configure provides. And no installation of guide happens yet anyways. --- doc/guide/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index c46ae0da1f..a9903ff1c8 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -4,7 +4,6 @@ if ENABLE_MAN # generated documentation DOCS = bind10-messages.html bind10-guide.html bind10-guide.txt -docdir = $(pkgdatadir)/doc/$(PACKAGE) doc_DATA = $(DOCS) bind10-guide.css # TODO: okay to include the generated bind10-messages.xml in dist tarfile too? From 41040dc27da86909c61187b8951f63f9d71c3dc7 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 31 May 2012 14:59:24 -0500 Subject: [PATCH 014/148] [trac1687]Revert "[trac1687] make man page generation on by default" This reverts commit 682df53277cfb545a1ba34a3a2198cb555cca6f5. Decided to not enable documentation by default for now. Need to handle build machines and make sure the doc generation environment is in place first. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a2370bbe19..6935431941 100644 --- a/configure.ac +++ b/configure.ac @@ -966,8 +966,8 @@ AC_SUBST(PERL) AC_PATH_PROGS(AWK, gawk awk) AC_SUBST(AWK) -AC_ARG_ENABLE(man, [AC_HELP_STRING([--disable-man], - [don't generate documentation])], enable_man=$enableval, enable_man=yes) +AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man], + [regenerate man pages [default=no]])], enable_man=$enableval, enable_man=no) AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno) From 0fec09f309665278bbc9e8ac291203290fe85e8f Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 1 Jun 2012 12:38:13 -0700 Subject: [PATCH 015/148] [trac1687] check and test xsltproc when using --enable-man check and test for xsltproc and the needed docbook stylesheets --- configure.ac | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6935431941..d3210cd128 100644 --- a/configure.ac +++ b/configure.ac @@ -967,7 +967,28 @@ AC_PATH_PROGS(AWK, gawk awk) AC_SUBST(AWK) AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man], - [regenerate man pages [default=no]])], enable_man=$enableval, enable_man=no) + [regenerate man pages using Docbook [default=no]])], + enable_man=$enableval, enable_man=no) + +# Check for xsltproc +if test "x$enable_man" != xno ; then + AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test -z "$XSLTPROC"; then + AC_MSG_ERROR("xsltproc not found; it is required for --enable-man") + else + AC_MSG_CHECKING([if $XSLTPROC works]) + # run xsltproc to see if works + $XSLTPROC --novalid --xinclude --nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl + if test $? -ne 0 ; then + AC_MSG_ERROR("Error with $XSLTPROC using release/xsl/current/manpages/docbook.xsl") + fi + $XSLTPROC --novalid --xinclude --nonet http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl + if test $? -ne 0 ; then + AC_MSG_ERROR("Error with $XSLTPROC using release/xsl/current/html/docbook.xsl") + fi + fi +fi + AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno) From 5b9ec6389bc87be6214a3e40cdfc3375e467f0ce Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 1 Jun 2012 12:39:31 -0700 Subject: [PATCH 016/148] [trac1687] remove built man page on make clean. (maybe this should be for maintainer clean only?) Use $XSLTPROC macro instead of xsltproc. Generate dummy manpage if --enable-man is not defined. This idea came from pango source tree. This is workaround so that the dist tarball includes the manpage. (Some is commented out; this is not complete yet.) This is because "make dist" needs the manpages but I don't want normal "make" builds to require building them due to more build dependencies. --- src/bin/bind10/Makefile.am | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am index 69ea256157..68940c9dab 100644 --- a/src/bin/bind10/Makefile.am +++ b/src/bin/bind10/Makefile.am @@ -17,12 +17,26 @@ bind10_DATA = bob.spec EXTRA_DIST = bob.spec man_MANS = bind10.8 +CLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) bind10.xml bind10_messages.mes if ENABLE_MAN bind10.8: bind10.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bind10.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bind10.xml + +#dist-local-check-mans-enabled: +# @if grep "Man generation disabled" $(man_MANS) >/dev/null; then $(RM) $(man_MANS); fi + +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + +#dist-local-check-mans-enabled: +# @echo "*** --enable-man must be used in order to make dist" +# @false endif From d4b87aa5746e3039b1ce78e0f5e9d87506159881 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 15 Jun 2012 08:07:18 -0500 Subject: [PATCH 017/148] [trac1687] output yes in configure output for finding dependencies for docs --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index d3210cd128..bfdbfe579c 100644 --- a/configure.ac +++ b/configure.ac @@ -986,6 +986,7 @@ if test "x$enable_man" != xno ; then if test $? -ne 0 ; then AC_MSG_ERROR("Error with $XSLTPROC using release/xsl/current/html/docbook.xsl") fi + AC_MSG_RESULT(yes) fi fi From 625cc0a45da9ee3356df3263d03a16eca5051b03 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 1 Aug 2012 17:40:00 +0200 Subject: [PATCH 018/148] [1959] Created TestControl class, unit tests and main function. --- tests/tools/perfdhcp/Makefile.am | 28 +- tests/tools/perfdhcp/main.cc | 46 ++++ tests/tools/perfdhcp/test_control.cc | 239 ++++++++++++++++++ tests/tools/perfdhcp/test_control.h | 117 +++++++++ tests/tools/perfdhcp/tests/Makefile.am | 2 + .../perfdhcp/tests/test_control_unittest.cc | 67 +++++ 6 files changed, 486 insertions(+), 13 deletions(-) create mode 100644 tests/tools/perfdhcp/main.cc create mode 100644 tests/tools/perfdhcp/test_control.cc create mode 100644 tests/tools/perfdhcp/test_control.h create mode 100644 tests/tools/perfdhcp/tests/test_control_unittest.cc diff --git a/tests/tools/perfdhcp/Makefile.am b/tests/tools/perfdhcp/Makefile.am index 6ebc00f92a..e9593df056 100644 --- a/tests/tools/perfdhcp/Makefile.am +++ b/tests/tools/perfdhcp/Makefile.am @@ -18,23 +18,25 @@ if USE_STATIC_LINK AM_LDFLAGS += -static endif -lib_LTLIBRARIES = libperfdhcp++.la -libperfdhcp___la_SOURCES = command_options.cc command_options.h -libperfdhcp___la_SOURCES += localized_option.h -libperfdhcp___la_SOURCES += perf_pkt6.cc perf_pkt6.h -libperfdhcp___la_SOURCES += perf_pkt4.cc perf_pkt4.h -libperfdhcp___la_SOURCES += pkt_transform.cc pkt_transform.h +pkglibexec_PROGRAMS = perfdhcp2 +perfdhcp2_SOURCES = main.cc +perfdhcp2_SOURCES += command_options.cc command_options.h +perfdhcp2_SOURCES += localized_option.h +perfdhcp2_SOURCES += perf_pkt6.cc perf_pkt6.h +perfdhcp2_SOURCES += perf_pkt4.cc perf_pkt4.h +perfdhcp2_SOURCES += pkt_transform.cc pkt_transform.h +perfdhcp2_SOURCES += test_control.cc test_control.h -libperfdhcp___la_CXXFLAGS = $(AM_CXXFLAGS) +perfdhcp2_CXXFLAGS = $(AM_CXXFLAGS) if USE_CLANGPP # Disable unused parameter warning caused by some of the # Boost headers when compiling with clang. -libperfdhcp___la_CXXFLAGS += -Wno-unused-parameter +perfdhcp2_CXXFLAGS += -Wno-unused-parameter endif -libperfdhcp___la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la -libperfdhcp___la_LIBADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la -libperfdhcp___la_LIBADD += $(top_builddir)/src/lib/asiolink/libasiolink.la +perfdhcp2_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la +perfdhcp2_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la +perfdhcp2_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la -pkglibexec_PROGRAMS = perfdhcp -perfdhcp_SOURCES = perfdhcp.c +#pkglibexec_PROGRAMS = perfdhcp +#perfdhcp_SOURCES = perfdhcp.c diff --git a/tests/tools/perfdhcp/main.cc b/tests/tools/perfdhcp/main.cc new file mode 100644 index 0000000000..d70b8fae8d --- /dev/null +++ b/tests/tools/perfdhcp/main.cc @@ -0,0 +1,46 @@ +// 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 +#include + +#include +#include + +#include "test_control.h" +#include "command_options.h" + +using namespace isc::perfdhcp; + +int +main(int argc, char* argv[]) { + CommandOptions& command_options = CommandOptions::instance(); + try { + command_options.parse(argc, argv); + } catch(isc::Exception& e) { + std::cout << "Error parsing command line options: " + << e.what() << std::endl; + command_options.usage(); + return(1); + } + try{ + TestControl& test_control = TestControl::instance(); + test_control.run(); + } catch (isc::Exception& e) { + std::cout << "Error starting perfdhcp: " << e.what() << std::endl; + return(1); + } + return(0); +} + diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc new file mode 100644 index 0000000000..728d4d58ec --- /dev/null +++ b/tests/tools/perfdhcp/test_control.cc @@ -0,0 +1,239 @@ +// 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 +#include +#include +#include + +#include + +#include +#include +#include +#include "test_control.h" +#include "command_options.h" + +using namespace std; +using namespace boost; +using namespace boost::posix_time; +using namespace isc; +using namespace isc::dhcp; + +namespace isc { +namespace perfdhcp { + +TestControl& +TestControl::instance() { + static TestControl test_control; + return (test_control); +} + +TestControl::TestControl() : + send_due_(microsec_clock::universal_time()), + last_sent_(send_due_) { +} + +bool +TestControl::checkExitConditions() const { + CommandOptions& options = CommandOptions::instance(); + if ((options.getNumRequests().size() > 0) && + (sent_packets_0_ >= options.getNumRequests()[0])) { + return(true); + } else if ((options.getNumRequests().size() == 2) && + (sent_packets_1_ >= options.getNumRequests()[1])) { + return(true); + } + return(false); +} + +Pkt4* +TestControl::createDiscoverPkt4() { + const uint32_t transid = static_cast(random()); + Pkt4* pkt4 = new Pkt4(DHCPDISCOVER, transid); + + OptionBuffer opt_request_list_buf(); + // createRequestListBuffer4(opt_request_list_buf); + return NULL; +} + +OptionPtr +TestControl::factoryRequestList4(Option::Universe u, + uint16_t type, + const OptionBuffer& buf) +{ + const uint8_t buf_array[] = { + DHO_SUBNET_MASK, + DHO_BROADCAST_ADDRESS, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_DOMAIN_NAME, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME + }; + + OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); + Option* opt = new Option(u, type, buf); + opt->setData(buf_with_options.begin(), + buf_with_options.end()); + return OptionPtr(opt); +} + +uint64_t +TestControl::getNextExchangesNum() const { + CommandOptions& options = CommandOptions::instance(); + // Reset number of exchanges. + uint64_t due_exchanges = 0; + // Get current time. + ptime now(microsec_clock::universal_time()); + // The due time indicates when we should start sening next chunk + // of packets. If it is already due time, we should calculate + // how many packets to send. + if (now >= send_due_) { + // If rate is specified from the command line we have to + // synchornize with it. + if (options.getRate() != 0) { + time_period period(send_due_, now); + // Null condition should not occur because we + // have checked it in the first if statement but + // let's keep this check just in case. + if (period.is_null()) { + return (0); + } + time_duration duration = period.length(); + // due_factor indicates the number of seconds that + // sending next chunk of packets will take. + double due_factor = duration.fractional_seconds() / + time_duration::ticks_per_second(); + due_factor += duration.total_seconds(); + // Multiplying due_factor by expected rate gives the number + // of exchanges to be initiated. + due_exchanges = static_cast(due_factor * options.getRate()); + // We want to make sure that at least one packet goes out. + due_exchanges += 1; + // We should not exceed aggressivity as it could have been + // restricted from command line. + if (due_exchanges > options.getAggressivity()) { + due_exchanges = options.getAggressivity(); + } + } else { + // Rate is not specified so we rely on aggressivity + // which is the number of packets to be sent in + // one chunk. + due_exchanges = options.getAggressivity(); + } + return (due_exchanges); + } + return (0); +} + +void +TestControl::registerOptionFactories4() const { + static bool factories_registered = false; + if (!factories_registered) { + LibDHCP::OptionFactoryRegister(Option::V4, + DHO_DHCP_PARAMETER_REQUEST_LIST, + &TestControl::factoryRequestList4); + } + factories_registered = true; +} + +void +TestControl::registerOptionFactories6() const { + static bool factories_registered = false; + if (!factories_registered) { + } + factories_registered = true; +} + +void +TestControl::registerOptionFactories() const { + CommandOptions& options = CommandOptions::instance(); + switch(options.getIpVersion()) { + case 4: + registerOptionFactories4(); + break; + case 6: + registerOptionFactories6(); + break; + default: + isc_throw(InvalidOperation, "command line options have to be parsed " + "before DHCP option factories can be registered"); + } +} + +void +TestControl::run() { + sent_packets_0_ = 0; + sent_packets_1_ = 0; + CommandOptions& options = CommandOptions::instance(); + // Ip version is not set ONLY in case the command options + // where not parsed. This surely means that parse() function + // was not called prior to starting the test. This is fatal + // error. + if (options.getIpVersion() == 0) { + isc_throw(InvalidOperation, "command options must be parsed before running " + "a test"); + } + registerOptionFactories(); + uint64_t packets_sent = 0; + for (;;) { + updateSendDue(); + if (checkExitConditions()) { + break; + } + uint64_t packets_due = getNextExchangesNum(); + for (uint64_t i = packets_due; i > 0; --i) { + startExchange(); + ++packets_sent; + cout << "Packets sent " << packets_sent << endl; + } + } + +} + +void +TestControl::startExchange() { + ++sent_packets_0_; + last_sent_ = microsec_clock::universal_time(); +} + +void +TestControl::updateSendDue() { + // If default constructor was called, this should not happen but + // if somebody has changed default constructor it is better to + // keep this check. + if (last_sent_.is_not_a_date_time()) { + isc_throw(Unexpected, "time of last sent packet not initialized"); + } + // Get the expected exchange rate. + CommandOptions& options = CommandOptions::instance(); + int rate = options.getRate(); + // If rate was not specified we will wait just one clock tick to + // send next packet. This simulates best effort conditions. + long duration = 1; + if (rate != 0) { + // We use number of ticks instead of nanoseconds because + // nanosecond resolution may not be available on some + // machines. Number of ticks guarantees the highest possible + // timer resolution. + duration = time_duration::ticks_per_second() / rate; + } + // Calculate due time to initate next chunk of exchanges. + send_due_ = last_sent_ + time_duration(0, 0, 0, duration); +} + + +} // namespace perfdhcp +} // namespace isc diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h new file mode 100644 index 0000000000..b1d7d27d32 --- /dev/null +++ b/tests/tools/perfdhcp/test_control.h @@ -0,0 +1,117 @@ +// 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 __TEST_CONTROL_H +#define __TEST_CONTROL_H + +#include +#include + +#include +#include + +#include +#include + +namespace isc { +namespace perfdhcp { + +/// \brief Test Control class. +/// +/// This class is responsible for running whole perfdhcp test. +/// +class TestControl : public boost::noncopyable { +public: + /// TestControl is a singleton class. This method returns reference + /// to its sole instance. + /// + /// \return the only existing instance of test control + static TestControl& instance(); + + /// Run performance test. + /// + /// Method runs whole performance test. Command line options must + /// be parsed prior to running this function. Othewise function will + /// throw exception. + /// + /// \throw isc::InvalidOperation if command line options are not parsed. + /// \throw isc::Unexpected if internal Test Controler error occured. + void run(); + +private: + + /// \brief Private default constructor. + /// + /// Default constructor is private as the object can be created + /// only via \ref instance method. + TestControl(); + + /// \brief Check if test exit condtitions fulfiled. + /// + /// Method checks if test exit conditions are fulfiled. + /// Exit conditions are checked periodically from the + /// main loop. Program should break the main loop when + /// this method returns true. It is calling function + /// responsibility to break main loop gracefully and + /// cleanup after test execution. + /// + /// \return true if any of the exit conditions is fulfiled. + bool checkExitConditions() const; + + dhcp::Pkt4* createDiscoverPkt4(); + + static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + + /// \brief Returns number of exchanges to be started. + /// + /// Method returns number of new exchanges to be started as soon + /// as possible to satisfy expected rate. Calculation used here + /// is based on current time, due time calculated with + /// \ref updateSendTime function and expected rate. + /// + /// \return number of exchanges to be started immediatelly. + uint64_t getNextExchangesNum() const; + + void registerOptionFactories4() const; + + void registerOptionFactories6() const; + + void registerOptionFactories() const; + + /// \brief Start new exchange of DHCP messages. + /// + void startExchange(); + + /// \brief Update due time to initiate next chunk of exchanges. + /// + /// Method updates due time to initiate next chunk of exchanges. + /// Function takes current time, last sent packet's time and + /// expected rate in its calculations. + void updateSendDue(); + + boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk + ///< of exchanges. + boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange + /// was initiated. + + uint64_t sent_packets_0_; + uint64_t sent_packets_1_; +}; + +} // namespace perfdhcp +} // namespace isc + +#endif // __COMMAND_OPTIONS_H diff --git a/tests/tools/perfdhcp/tests/Makefile.am b/tests/tools/perfdhcp/tests/Makefile.am index ab1251c5c9..000bab527b 100644 --- a/tests/tools/perfdhcp/tests/Makefile.am +++ b/tests/tools/perfdhcp/tests/Makefile.am @@ -21,10 +21,12 @@ run_unittests_SOURCES += command_options_unittest.cc run_unittests_SOURCES += perf_pkt6_unittest.cc run_unittests_SOURCES += perf_pkt4_unittest.cc run_unittests_SOURCES += localized_option_unittest.cc +run_unittests_SOURCES += test_control_unittest.cc run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/command_options.cc run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/pkt_transform.cc run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt6.cc run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt4.cc +run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/test_control.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc new file mode 100644 index 0000000000..7a66b03fb3 --- /dev/null +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -0,0 +1,67 @@ +// 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 +#include +#include +#include + +#include "../test_control.h" +#include "../command_options.h" +#include "exceptions/exceptions.h" + +using namespace std; +using namespace isc; +using namespace isc::perfdhcp; + +/// \brief Test Fixture Class +/// +/// This test fixture class is used to perform +/// unit tests on perfdhcp TestControl class. +class TestControlTest : public virtual ::testing::Test +{ +public: + /// \brief Default Constructor + TestControlTest() { } + +protected: +}; + +TEST_F(TestControlTest, Run) { + // Get the instance of TestControl object. + TestControl& test_control = TestControl::instance(); + // Running test without parsing command line arguments is + // expected to cause exception. + EXPECT_THROW(test_control.run(), isc::InvalidOperation); + + // The command line is to run single test iteration and exit. + // We have to declare argv as const walk around the problem + // of deprecated conversion from string to char*. + const char* argv[] = { "perfdhcp", "-l", "eth0", "-r", "10", "-n", "1" }; + const int argc = sizeof(argv) / sizeof(argv[0]); + CommandOptions& options = CommandOptions::instance(); + + // const_cast is odd but it seems to be the most straight forward way + // to achive the goal. In the future we might think about creating + // a tokenizing function that would dynamically produce non-const + // argv value. + ASSERT_NO_THROW(options.parse(argc, const_cast(argv))); + EXPECT_NO_THROW(test_control.run()); + + // This is ok to run the test again with the same parameters. + // It may trigger exception if TestControl singleton is in + // invalid state after test run. We want to make sure it is + // safe to rerun the test. + EXPECT_NO_THROW(test_control.run()); +} From 8935b6716b3795bb889641a3127c2a701c6cac59 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 1 Aug 2012 17:41:28 +0200 Subject: [PATCH 019/148] [1959] Added factory function to create instance of options. --- src/lib/dhcp/libdhcp++.cc | 26 ++++++++++ src/lib/dhcp/libdhcp++.h | 25 +++++++++- src/lib/dhcp/option.cc | 8 +++ src/lib/dhcp/option.h | 17 +++++++ src/lib/dhcp/tests/libdhcp++_unittest.cc | 63 ++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 2 deletions(-) diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc index c054a4b0a5..4ff07eac6a 100644 --- a/src/lib/dhcp/libdhcp++.cc +++ b/src/lib/dhcp/libdhcp++.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "config.h" #include @@ -34,6 +35,31 @@ std::map LibDHCP::v4factories_; std::map LibDHCP::v6factories_; +OptionPtr +LibDHCP::optionFactory(Option::Universe u, + uint16_t type, + const OptionBuffer& buf) { + FactoryMap::iterator it; + if (u == Option::V4) { + it = v4factories_.find(type); + if (it == v4factories_.end()) { + isc_throw(BadValue, "factory function not registered " + "for DHCP v4 option type " << type); + } + } else if (u == Option::V6) { + it = v6factories_.find(type); + if (it == v6factories_.end()) { + isc_throw(BadValue, "factory function not registered " + "for DHCPv6 option type " << type); + } + } else { + isc_throw(BadValue, "invalid universe specified (expected " + "Option::V4 or Option::V6"); + } + return(it->second(u, type, buf)); +} + + size_t LibDHCP::unpackOptions6(const OptionBuffer& buf, isc::dhcp::Option::OptionCollection& options) { size_t offset = 0; diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h index c7935c8ff3..c959609c61 100644 --- a/src/lib/dhcp/libdhcp++.h +++ b/src/lib/dhcp/libdhcp++.h @@ -25,6 +25,27 @@ namespace dhcp { class LibDHCP { public: + + /// Map of factory functions. + typedef std::map FactoryMap; + + /// @brief Factory function to create instance of option. + /// + /// Factory method creates instance of specified option. The option + /// to be created has to have corresponding factory function + /// registered with \ref LibDHCP::OptionFactoryRegister. + /// + /// @param u universe of the option (V4 or V6) + /// @param type option-type + /// @param buf option-buffer + /// @throw isc::InvalidOperation if there is no factory function + /// registered for specified option type. + /// @return instance of option. + static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u, + uint16_t type, + const OptionBuffer& buf); + + /// Builds collection of options. /// /// Builds raw (on-wire) data for provided collection of options. @@ -84,10 +105,10 @@ public: Option::Factory * factory); protected: /// pointers to factories that produce DHCPv6 options - static std::map v4factories_; + static FactoryMap v4factories_; /// pointers to factories that produce DHCPv6 options - static std::map v6factories_; + static FactoryMap v6factories_; }; } diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc index 0c71606b6c..fb441f93d1 100644 --- a/src/lib/dhcp/option.cc +++ b/src/lib/dhcp/option.cc @@ -29,6 +29,14 @@ using namespace isc::util; namespace isc { namespace dhcp { +OptionPtr +Option::factory(Option::Universe u, + uint16_t type, + const OptionBuffer& buf) { + return(LibDHCP::optionFactory(u, type, buf)); +} + + Option::Option(Universe u, uint16_t type) :universe_(u), type_(type) { diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h index 066296704e..051b15dd4e 100644 --- a/src/lib/dhcp/option.h +++ b/src/lib/dhcp/option.h @@ -66,6 +66,23 @@ public: /// @return a pointer to a created option object typedef OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer& buf); + /// @brief Factory function to create instance of option. + /// + /// Factory method creates instance of specified option. The option + /// to be created has to have corresponding factory function + /// registered with \ref LibDHCP::OptionFactoryRegister. + /// + /// @param u universe of the option (V4 or V6) + /// @param type option-type + /// @param buf option-buffer + /// @throw isc::InvalidOperation if there is no factory function + /// registered for specified option type. + /// @return instance of option. + static OptionPtr factory(Option::Universe u, + uint16_t type, + const OptionBuffer& buf); + + /// @brief ctor, used for options constructed, usually during transmission /// /// @param u option universe (DHCPv4 or DHCPv6) diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index 7e18be6889..ac758bed9c 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include "config.h" @@ -31,6 +33,19 @@ class LibDhcpTest : public ::testing::Test { public: LibDhcpTest() { } + + /// @brief Generic factory function to create any option. + /// + /// Generic factory function to create any option. + /// + /// @param u universe (V4 or V6) + /// @param type option-type + /// @param buf option-buffer + static OptionPtr genericOptionFactory(Option::Universe u, uint16_t type, + const OptionBuffer& buf) { + Option* option = new Option(u, type, buf); + return OptionPtr(option); + } }; static const uint8_t packed[] = { @@ -41,6 +56,54 @@ static const uint8_t packed[] = { 1, 1, 0, 1, 114 // opt5 (5 bytes) }; +TEST(LibDhcpTest, optionFactory) { + OptionBuffer buf; + // Factory functions for specific options must be registered before + // they can be used to create options instances. Otherwise exception + // is rised. + EXPECT_THROW(LibDHCP::optionFactory(Option::V4, DHO_SUBNET_MASK, buf), + isc::BadValue); + + // Let's register some factory functions (two v4 and one v6 function). + // Registration may trigger exception if function for the specified + // option has been registered already. + ASSERT_NO_THROW( + LibDHCP::OptionFactoryRegister(Option::V4, DHO_SUBNET_MASK, + &LibDhcpTest::genericOptionFactory); + ); + ASSERT_NO_THROW( + LibDHCP::OptionFactoryRegister(Option::V4, DHO_TIME_OFFSET, + &LibDhcpTest::genericOptionFactory); + ); + ASSERT_NO_THROW( + LibDHCP::OptionFactoryRegister(Option::V6, D6O_CLIENTID, + &LibDhcpTest::genericOptionFactory); + ); + + // Invoke factory functions for all options (check if registration + // was successful). + OptionPtr opt_subnet_mask; + opt_subnet_mask = LibDHCP::optionFactory(Option::V4, + DHO_SUBNET_MASK, + buf); + // Check if non-NULL DHO_SUBNET_MASK option pointer has been returned. + EXPECT_TRUE(opt_subnet_mask); + + OptionPtr opt_time_offset; + opt_time_offset = LibDHCP::optionFactory(Option::V4, + DHO_TIME_OFFSET, + buf); + // Check if non-NULL DHO_TIME_OFFSET option pointer has been returned. + EXPECT_TRUE(opt_time_offset); + + OptionPtr opt_clientid; + opt_clientid = LibDHCP::optionFactory(Option::V6, + D6O_CLIENTID, + buf); + // Check if non-NULL D6O_CLIENTID option pointer has been returned. + EXPECT_TRUE(opt_clientid); +} + TEST(LibDhcpTest, packOptions6) { OptionBuffer buf(512); isc::dhcp::Option::OptionCollection opts; // list of options From 1bb01f6f6ca354f10def4d35850a782d2ae348a0 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 1 Aug 2012 18:08:05 +0200 Subject: [PATCH 020/148] [1959] Use factory function to create option's instance. --- src/lib/dhcp/option.h | 17 +++++++++++++++++ tests/tools/perfdhcp/test_control.cc | 19 +++++++++++-------- tests/tools/perfdhcp/test_control.h | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h index 051b15dd4e..37069d6df5 100644 --- a/src/lib/dhcp/option.h +++ b/src/lib/dhcp/option.h @@ -82,6 +82,23 @@ public: uint16_t type, const OptionBuffer& buf); + /// @brief Factory function to create instance of option. + /// + /// Factory method creates instance of specified option. The option + /// to be created has to have corresponding factory function + /// registered with \ref LibDHCP::OptionFactoryRegister. + /// This method creates empty \ref OptionBuffer object. Use this + /// factory function if it is not needed to pass custom buffer. + /// + /// @param u universe of the option (V4 or V6) + /// @param type option-type + /// @throw isc::InvalidOperation if there is no factory function + /// registered for specified option type. + /// @return instance of option. + static OptionPtr factory(Option::Universe u, uint16_t type) { + return factory(u, type, OptionBuffer()); + } + /// @brief ctor, used for options constructed, usually during transmission /// diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 728d4d58ec..8072e75461 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -58,14 +58,18 @@ TestControl::checkExitConditions() const { return(false); } -Pkt4* -TestControl::createDiscoverPkt4() { +boost::shared_ptr +TestControl::createDiscoverPkt4() const { const uint32_t transid = static_cast(random()); - Pkt4* pkt4 = new Pkt4(DHCPDISCOVER, transid); + boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); + if (!pkt4) { + isc_throw(isc::Unexpected, "failed to create DISCOVER packet"); + } - OptionBuffer opt_request_list_buf(); - // createRequestListBuffer4(opt_request_list_buf); - return NULL; + OptionPtr request_list_option = + Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST); + pkt4->addOption(request_list_option); + return pkt4; } OptionPtr @@ -85,8 +89,7 @@ TestControl::factoryRequestList4(Option::Universe u, OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); Option* opt = new Option(u, type, buf); - opt->setData(buf_with_options.begin(), - buf_with_options.end()); + opt->setData(buf_with_options.begin(), buf_with_options.end()); return OptionPtr(opt); } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index b1d7d27d32..ce5aa4c4b6 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -69,7 +69,7 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; - dhcp::Pkt4* createDiscoverPkt4(); + boost::shared_ptr createDiscoverPkt4() const; static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, From 7836678d112b7d8c250963c34f0431641d9946e9 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 2 Aug 2012 11:50:44 -0500 Subject: [PATCH 021/148] [1687] make sure sockcreator manual is installed --- src/bin/sockcreator/Makefile.am | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index 8494114bcd..6ac494f92a 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -12,6 +12,16 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = *.gcno *.gcda +man_MANS = b10-sockcreator.8 +EXTRA_DIST = $(man_MANS) b10-sockcreator.xml + +if ENABLE_MAN + +b10-sockcreator.8: b10-sockcreator.xml + xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-sockcreator.xml + +endif + pkglibexec_PROGRAMS = b10-sockcreator b10_sockcreator_SOURCES = sockcreator.cc sockcreator.h main.cc From 83a51075c389a4d913b8f83e9ad0969e8d86f650 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 2 Aug 2012 17:56:27 -0500 Subject: [PATCH 022/148] [1687] remove this generated man page --- src/bin/showtech/b10-showtech.1 | 66 --------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 src/bin/showtech/b10-showtech.1 diff --git a/src/bin/showtech/b10-showtech.1 b/src/bin/showtech/b10-showtech.1 deleted file mode 100644 index b331713409..0000000000 --- a/src/bin/showtech/b10-showtech.1 +++ /dev/null @@ -1,66 +0,0 @@ -'\" t -.\" Title: b10-showtech -.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.76.1 -.\" Date: June 26, 2012 -.\" Manual: BIND10 -.\" Source: BIND10 -.\" Language: English -.\" -.TH "B10\-SHOWTECH" "1" "June 26, 2012" "BIND10" "BIND10" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -b10-showtech \- BIND 10 system information display tool -.SH "SYNOPSIS" -.HP \w'\fBb10\-showtech\fR\ 'u -\fBb10\-showtech\fR -.SH "DESCRIPTION" -.PP -The -\fBb10\-showtech\fR -program collects and outputs a variety of information about the system that BIND 10 is running on\&. This information can be useful to people involved in debugging and technical support\&. -.SH "ARGUMENTS" -.PP -\-h -.RS 4 -Displays usage instructions\&. -.RE -.PP -\-o \fIoutput\-file\fR -.RS 4 -If an output file is specified, the output of -\fBb10\-showtech\fR -is written to this file\&. By default, the output is written to standard output\&. -.RE -.SH "SEE ALSO" -.PP - -\fBbind10\fR(8), -BIND 10 Guide\&. -.SH "HISTORY" -.PP -The -\fBb10\-showtech\fR -daemon was initially implemented by ISC staff in June, 2012\&. -.SH "COPYRIGHT" -.br -Copyright \(co 2012 Internet Systems Consortium, Inc. ("ISC") -.br From 4ed645f5f18fe5a49a4d37a27d84ae1983a628da Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 2 Aug 2012 17:59:46 -0500 Subject: [PATCH 023/148] [1687] makefile updates, mostly to generate dummy manpage if not enabled --- src/bin/auth/Makefile.am | 7 +++++++ src/bin/bindctl/Makefile.am | 9 ++++++++- src/bin/cfgmgr/Makefile.am | 9 ++++++++- src/bin/cmdctl/Makefile.am | 7 +++++++ src/bin/dbutil/Makefile.am | 7 +++++++ src/bin/ddns/Makefile.am | 8 ++++++++ src/bin/dhcp4/Makefile.am | 8 ++++++++ src/bin/dhcp6/Makefile.am | 8 ++++++++ src/bin/host/Makefile.am | 7 +++++++ src/bin/loadzone/Makefile.am | 7 +++++++ src/bin/msgq/Makefile.am | 7 +++++++ src/bin/resolver/Makefile.am | 7 +++++++ src/bin/showtech/Makefile.am | 7 +++++++ src/bin/sockcreator/Makefile.am | 7 +++++++ src/bin/stats/Makefile.am | 7 +++++++ src/bin/usermgr/Makefile.am | 7 +++++++ src/bin/xfrin/Makefile.am | 7 +++++++ src/bin/xfrout/Makefile.am | 7 +++++++ src/bin/zonemgr/Makefile.am | 7 +++++++ 19 files changed, 138 insertions(+), 2 deletions(-) diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index 1f0fbbf63f..9a6183f7e6 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -20,6 +20,7 @@ CLEANFILES = *.gcno *.gcda auth.spec spec_config.h CLEANFILES += auth_messages.h auth_messages.cc man_MANS = b10-auth.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-auth.xml if ENABLE_MAN @@ -27,6 +28,12 @@ if ENABLE_MAN b10-auth.8: b10-auth.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-auth.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif auth.spec: auth.spec.pre diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am index 52a5145c85..1e41345a30 100644 --- a/src/bin/bindctl/Makefile.am +++ b/src/bin/bindctl/Makefile.am @@ -14,11 +14,18 @@ pythondir = $(pyexecdir)/bindctl bindctldir = $(pkgdatadir) CLEANFILES = bindctl bindctl_main.pyc +CLEANFILES += $(man_MANS) if ENABLE_MAN bindctl.1: bindctl.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bindctl.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bindctl.xml + +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ endif diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am index aee78cf995..99feed564e 100644 --- a/src/bin/cfgmgr/Makefile.am +++ b/src/bin/cfgmgr/Makefile.am @@ -10,12 +10,19 @@ b10_cfgmgrdir = @localstatedir@/@PACKAGE@ #B10_cfgmgr_DATA = man_MANS = b10-cfgmgr.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cfgmgr.xml if ENABLE_MAN b10-cfgmgr.8: b10-cfgmgr.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cfgmgr.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cfgmgr.xml + +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ endif diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am index e302fa6b87..e115366587 100644 --- a/src/bin/cmdctl/Makefile.am +++ b/src/bin/cmdctl/Makefile.am @@ -26,6 +26,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.pyc man_MANS = b10-cmdctl.8 +CLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes if ENABLE_MAN @@ -33,6 +34,12 @@ if ENABLE_MAN b10-cmdctl.8: b10-cmdctl.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif cmdctl.spec: cmdctl.spec.pre diff --git a/src/bin/dbutil/Makefile.am b/src/bin/dbutil/Makefile.am index e05055f8f9..0d1b3666f5 100644 --- a/src/bin/dbutil/Makefile.am +++ b/src/bin/dbutil/Makefile.am @@ -14,12 +14,19 @@ CLEANFILES = b10-dbutil b10-dbutil.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyo +CLEANFILES += $(man_MANS) if ENABLE_MAN b10-dbutil.8: b10-dbutil.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-dbutil.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # Define rule to build logging source files from message file diff --git a/src/bin/ddns/Makefile.am b/src/bin/ddns/Makefile.am index 0b014cb1ad..fa2a2ce2f1 100644 --- a/src/bin/ddns/Makefile.am +++ b/src/bin/ddns/Makefile.am @@ -15,7 +15,9 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/ddns_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/ddns_messages.pyc EXTRA_DIST = ddns_messages.mes ddns.spec + man_MANS = b10-ddns.8 +CLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) b10-ddns.xml if ENABLE_MAN @@ -23,6 +25,12 @@ if ENABLE_MAN b10-ddns.8: b10-ddns.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-ddns.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # Define rule to build logging source files from message file diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index d343633c75..5afffcab30 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -15,6 +15,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp4.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec if ENABLE_MAN @@ -22,6 +23,13 @@ b10-dhcp4.8: b10-dhcp4.xml xsltproc --novalid --xinclude --nonet -o $@ \ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ $(srcdir)/b10-dhcp4.xml + +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif spec_config.h: spec_config.h.pre diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 16b17eddf8..8cd76196ff 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -16,6 +16,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp6.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec if ENABLE_MAN @@ -24,6 +25,13 @@ b10-dhcp6.8: b10-dhcp6.xml xsltproc --novalid --xinclude --nonet -o $@ \ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ $(srcdir)/b10-dhcp6.xml + +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif spec_config.h: spec_config.h.pre diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am index a8f96c21fe..d9ee9a7e08 100644 --- a/src/bin/host/Makefile.am +++ b/src/bin/host/Makefile.am @@ -17,6 +17,7 @@ b10_host_LDADD += $(top_builddir)/src/lib/util/libutil.la b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la man_MANS = b10-host.1 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-host.xml .PHONY: man @@ -27,4 +28,10 @@ man: b10-host.1 b10-host.1: b10-host.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-host.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif diff --git a/src/bin/loadzone/Makefile.am b/src/bin/loadzone/Makefile.am index a235d68bd0..9478b208d5 100644 --- a/src/bin/loadzone/Makefile.am +++ b/src/bin/loadzone/Makefile.am @@ -5,6 +5,7 @@ noinst_SCRIPTS = run_loadzone.sh CLEANFILES = b10-loadzone man_MANS = b10-loadzone.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-loadzone.xml if ENABLE_MAN @@ -12,6 +13,12 @@ if ENABLE_MAN b10-loadzone.8: b10-loadzone.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-loadzone.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif b10-loadzone: b10-loadzone.py diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am index 908cab5dfd..6b137ba61f 100644 --- a/src/bin/msgq/Makefile.am +++ b/src/bin/msgq/Makefile.am @@ -7,6 +7,7 @@ pkglibexec_SCRIPTS = b10-msgq CLEANFILES = b10-msgq msgq.pyc man_MANS = b10-msgq.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) msgq.xml if ENABLE_MAN @@ -14,6 +15,12 @@ if ENABLE_MAN b10-msgq.8: msgq.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/msgq.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index 2bb3768aba..ace01ea48a 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -23,6 +23,7 @@ CLEANFILES += resolver.spec spec_config.h CLEANFILES += resolver_messages.cc resolver_messages.h man_MANS = b10-resolver.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-resolver.xml resolver_messages.mes if ENABLE_MAN @@ -30,6 +31,12 @@ if ENABLE_MAN b10-resolver.8: b10-resolver.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-resolver.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif resolver.spec: resolver.spec.pre diff --git a/src/bin/showtech/Makefile.am b/src/bin/showtech/Makefile.am index cc9923c884..ae8118dab9 100644 --- a/src/bin/showtech/Makefile.am +++ b/src/bin/showtech/Makefile.am @@ -12,12 +12,19 @@ MAN1_FILES = \ man_MANS = \ $(MAN1_FILES:.xml=.1) +CLEANFILES += $(man_MANS) if ENABLE_MAN .xml.1: xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif EXTRA_DIST = $(man_MANS) $(MAN1_FILES) diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index 6ac494f92a..72094f9555 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -13,6 +13,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = *.gcno *.gcda man_MANS = b10-sockcreator.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-sockcreator.xml if ENABLE_MAN @@ -20,6 +21,12 @@ if ENABLE_MAN b10-sockcreator.8: b10-sockcreator.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-sockcreator.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif pkglibexec_PROGRAMS = b10-sockcreator diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am index 63e2a3b38b..60410a69a2 100644 --- a/src/bin/stats/Makefile.am +++ b/src/bin/stats/Makefile.am @@ -20,6 +20,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.pyc man_MANS = b10-stats.8 b10-stats-httpd.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-stats.xml b10-stats-httpd.xml EXTRA_DIST += stats.spec stats-httpd.spec EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl @@ -33,6 +34,12 @@ b10-stats.8: b10-stats.xml b10-stats-httpd.8: b10-stats-httpd.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats-httpd.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif $(PYTHON_LOGMSGPKG_DIR)/work/stats_messages.py : stats_messages.mes diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am index 7ebb1cd6c2..5f427ace84 100644 --- a/src/bin/usermgr/Makefile.am +++ b/src/bin/usermgr/Makefile.am @@ -5,6 +5,7 @@ b10_cmdctl_usermgrdir = $(pkgdatadir) CLEANFILES= b10-cmdctl-usermgr man_MANS = b10-cmdctl-usermgr.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cmdctl-usermgr.xml if ENABLE_MAN @@ -12,6 +13,12 @@ if ENABLE_MAN b10-cmdctl-usermgr.8: b10-cmdctl-usermgr.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl-usermgr.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am index 8d80b220fb..091be9bcdb 100644 --- a/src/bin/xfrin/Makefile.am +++ b/src/bin/xfrin/Makefile.am @@ -15,6 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.pyc man_MANS = b10-xfrin.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrin.xml EXTRA_DIST += xfrin.spec xfrin_messages.mes @@ -23,6 +24,12 @@ if ENABLE_MAN b10-xfrin.8: b10-xfrin.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrin.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # Define rule to build logging source files from message file diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am index 6100e64bf7..8adec7f73f 100644 --- a/src/bin/xfrout/Makefile.am +++ b/src/bin/xfrout/Makefile.am @@ -15,6 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.pyc man_MANS = b10-xfrout.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrout.xml xfrout_messages.mes if ENABLE_MAN @@ -22,6 +23,12 @@ if ENABLE_MAN b10-xfrout.8: b10-xfrout.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrout.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # Define rule to build logging source files from message file diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am index aa427fdf2e..8244fb6dc9 100644 --- a/src/bin/zonemgr/Makefile.am +++ b/src/bin/zonemgr/Makefile.am @@ -15,6 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.pyc man_MANS = b10-zonemgr.8 +CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-zonemgr.xml zonemgr_messages.mes if ENABLE_MAN @@ -22,6 +23,12 @@ if ENABLE_MAN b10-zonemgr.8: b10-zonemgr.xml xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-zonemgr.xml +else + +$(man_MANS): + @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif # Build logging source file from message files From 777bf970e37efcbda7222476e67d4ebb2ee7dfca Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 2 Aug 2012 20:06:04 -0500 Subject: [PATCH 024/148] [1687] use @XSLTPROC@ macro instead of xsltproc to get the full path if needed also fixed one target that had spaces instead of tab --- doc/guide/Makefile.am | 4 ++-- src/bin/auth/Makefile.am | 2 +- src/bin/cmdctl/Makefile.am | 2 +- src/bin/dbutil/Makefile.am | 2 +- src/bin/ddns/Makefile.am | 2 +- src/bin/dhcp4/Makefile.am | 2 +- src/bin/dhcp6/Makefile.am | 2 +- src/bin/host/Makefile.am | 2 +- src/bin/loadzone/Makefile.am | 2 +- src/bin/msgq/Makefile.am | 2 +- src/bin/resolver/Makefile.am | 2 +- src/bin/showtech/Makefile.am | 2 +- src/bin/sockcreator/Makefile.am | 2 +- src/bin/stats/Makefile.am | 4 ++-- src/bin/usermgr/Makefile.am | 2 +- src/bin/xfrin/Makefile.am | 2 +- src/bin/xfrout/Makefile.am | 2 +- src/bin/zonemgr/Makefile.am | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index 94dfeb0404..895716d87d 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -13,7 +13,7 @@ EXTRA_DIST = bind10-guide.xml bind10-messages.xml CLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml bind10-guide.html: bind10-guide.xml - xsltproc --novalid --xinclude --nonet \ + @XSLTPROC@ --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ -o $@ \ --stringparam section.autolabel 1 \ @@ -28,7 +28,7 @@ bind10-guide.txt: bind10-guide.html $(HTML2TXT) bind10-guide.html > $@ bind10-messages.html: bind10-messages.xml - xsltproc --novalid --xinclude --nonet \ + @XSLTPROC@ --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ -o $@ \ --stringparam html.stylesheet $(srcdir)/bind10-guide.css \ diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index 9a6183f7e6..eb5b8efe48 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -26,7 +26,7 @@ EXTRA_DIST = $(man_MANS) b10-auth.xml if ENABLE_MAN b10-auth.8: b10-auth.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-auth.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-auth.xml else diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am index e115366587..e6a8d5eeb5 100644 --- a/src/bin/cmdctl/Makefile.am +++ b/src/bin/cmdctl/Makefile.am @@ -32,7 +32,7 @@ EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes if ENABLE_MAN b10-cmdctl.8: b10-cmdctl.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml else diff --git a/src/bin/dbutil/Makefile.am b/src/bin/dbutil/Makefile.am index 0d1b3666f5..c15bdecb97 100644 --- a/src/bin/dbutil/Makefile.am +++ b/src/bin/dbutil/Makefile.am @@ -19,7 +19,7 @@ CLEANFILES += $(man_MANS) if ENABLE_MAN b10-dbutil.8: b10-dbutil.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-dbutil.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-dbutil.xml else diff --git a/src/bin/ddns/Makefile.am b/src/bin/ddns/Makefile.am index fa2a2ce2f1..2f99e81af3 100644 --- a/src/bin/ddns/Makefile.am +++ b/src/bin/ddns/Makefile.am @@ -23,7 +23,7 @@ EXTRA_DIST += $(man_MANS) b10-ddns.xml if ENABLE_MAN b10-ddns.8: b10-ddns.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-ddns.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-ddns.xml else diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index 5afffcab30..ad5f461445 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -20,7 +20,7 @@ EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec if ENABLE_MAN b10-dhcp4.8: b10-dhcp4.xml - xsltproc --novalid --xinclude --nonet -o $@ \ + @XSLTPROC@ --novalid --xinclude --nonet -o $@ \ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ $(srcdir)/b10-dhcp4.xml diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 8cd76196ff..43e109d621 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -22,7 +22,7 @@ EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec if ENABLE_MAN b10-dhcp6.8: b10-dhcp6.xml - xsltproc --novalid --xinclude --nonet -o $@ \ + @XSLTPROC@ --novalid --xinclude --nonet -o $@ \ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ $(srcdir)/b10-dhcp6.xml diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am index d9ee9a7e08..e64ac933eb 100644 --- a/src/bin/host/Makefile.am +++ b/src/bin/host/Makefile.am @@ -26,7 +26,7 @@ if ENABLE_MAN man: b10-host.1 b10-host.1: b10-host.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-host.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-host.xml else diff --git a/src/bin/loadzone/Makefile.am b/src/bin/loadzone/Makefile.am index 9478b208d5..175a67a10e 100644 --- a/src/bin/loadzone/Makefile.am +++ b/src/bin/loadzone/Makefile.am @@ -11,7 +11,7 @@ EXTRA_DIST = $(man_MANS) b10-loadzone.xml if ENABLE_MAN b10-loadzone.8: b10-loadzone.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-loadzone.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-loadzone.xml else diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am index 6b137ba61f..25b0dc7b90 100644 --- a/src/bin/msgq/Makefile.am +++ b/src/bin/msgq/Makefile.am @@ -13,7 +13,7 @@ EXTRA_DIST = $(man_MANS) msgq.xml if ENABLE_MAN b10-msgq.8: msgq.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/msgq.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/msgq.xml else diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index ace01ea48a..3bb0d3c030 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -29,7 +29,7 @@ EXTRA_DIST = $(man_MANS) b10-resolver.xml resolver_messages.mes if ENABLE_MAN b10-resolver.8: b10-resolver.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-resolver.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-resolver.xml else diff --git a/src/bin/showtech/Makefile.am b/src/bin/showtech/Makefile.am index ae8118dab9..8ee078e903 100644 --- a/src/bin/showtech/Makefile.am +++ b/src/bin/showtech/Makefile.am @@ -17,7 +17,7 @@ CLEANFILES += $(man_MANS) if ENABLE_MAN .xml.1: - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< else diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index 72094f9555..a57f4aa814 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -19,7 +19,7 @@ EXTRA_DIST = $(man_MANS) b10-sockcreator.xml if ENABLE_MAN b10-sockcreator.8: b10-sockcreator.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-sockcreator.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-sockcreator.xml else diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am index 60410a69a2..88592e6b02 100644 --- a/src/bin/stats/Makefile.am +++ b/src/bin/stats/Makefile.am @@ -29,10 +29,10 @@ EXTRA_DIST += stats_messages.mes stats_httpd_messages.mes if ENABLE_MAN b10-stats.8: b10-stats.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml b10-stats-httpd.8: b10-stats-httpd.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats-httpd.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats-httpd.xml else diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am index 5f427ace84..68bf3e596e 100644 --- a/src/bin/usermgr/Makefile.am +++ b/src/bin/usermgr/Makefile.am @@ -11,7 +11,7 @@ EXTRA_DIST = $(man_MANS) b10-cmdctl-usermgr.xml if ENABLE_MAN b10-cmdctl-usermgr.8: b10-cmdctl-usermgr.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl-usermgr.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl-usermgr.xml else diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am index 091be9bcdb..b9434db46a 100644 --- a/src/bin/xfrin/Makefile.am +++ b/src/bin/xfrin/Makefile.am @@ -22,7 +22,7 @@ EXTRA_DIST += xfrin.spec xfrin_messages.mes if ENABLE_MAN b10-xfrin.8: b10-xfrin.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrin.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrin.xml else diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am index 8adec7f73f..c07f0693c6 100644 --- a/src/bin/xfrout/Makefile.am +++ b/src/bin/xfrout/Makefile.am @@ -21,7 +21,7 @@ EXTRA_DIST = $(man_MANS) b10-xfrout.xml xfrout_messages.mes if ENABLE_MAN b10-xfrout.8: b10-xfrout.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrout.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrout.xml else diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am index 8244fb6dc9..7956326d49 100644 --- a/src/bin/zonemgr/Makefile.am +++ b/src/bin/zonemgr/Makefile.am @@ -21,7 +21,7 @@ EXTRA_DIST = $(man_MANS) b10-zonemgr.xml zonemgr_messages.mes if ENABLE_MAN b10-zonemgr.8: b10-zonemgr.xml - xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-zonemgr.xml + @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-zonemgr.xml else From d7d8c3a081dfa87645cacf3b04260916095d6f49 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 2 Aug 2012 20:23:56 -0500 Subject: [PATCH 025/148] [1687] generate dummy docs here too --- doc/guide/Makefile.am | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index 895716d87d..79d5d33ba8 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -1,6 +1,3 @@ -# This is not a "man" manual, but reuse this for now for docbook. -if ENABLE_MAN - # generated documentation HTMLDOCS = bind10-guide.html bind10-messages.html DOCS = bind10-guide.txt @@ -8,10 +5,12 @@ DOCS = bind10-guide.txt dist_doc_DATA = $(DOCS) dist_html_DATA = $(HTMLDOCS) bind10-guide.css -# TODO: okay to include the generated bind10-messages.xml in dist tarfile too? -EXTRA_DIST = bind10-guide.xml bind10-messages.xml +EXTRA_DIST = bind10-guide.xml CLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml +# This is not a "man" manual, but reuse this for now for docbook. +if ENABLE_MAN + bind10-guide.html: bind10-guide.xml @XSLTPROC@ --novalid --xinclude --nonet \ --path $(top_builddir)/doc \ @@ -38,4 +37,10 @@ bind10-messages.html: bind10-messages.xml bind10-messages.xml: $(PYTHON) $(top_srcdir)/tools/system_messages.py -o $@ $(top_srcdir) +else + +$(HTMLDOCS) $(DOCS): + @echo Doc generation disabled. Creating dummy $@. Configure with --enable-man to enable it. + @echo Doc generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + endif From 932ddbdd34e4a84fdddff9dacb575ec87e72e17c Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 2 Aug 2012 20:55:20 -0500 Subject: [PATCH 026/148] [1687] rename configure's --enable-man to --enable-generate-docs --- configure.ac | 14 +++++++------- doc/guide/Makefile.am | 6 +++--- src/bin/auth/Makefile.am | 6 +++--- src/bin/bind10/Makefile.am | 8 ++++---- src/bin/bindctl/Makefile.am | 6 +++--- src/bin/cfgmgr/Makefile.am | 6 +++--- src/bin/cmdctl/Makefile.am | 6 +++--- src/bin/dbutil/Makefile.am | 6 +++--- src/bin/ddns/Makefile.am | 6 +++--- src/bin/dhcp4/Makefile.am | 6 +++--- src/bin/dhcp6/Makefile.am | 6 +++--- src/bin/host/Makefile.am | 6 +++--- src/bin/loadzone/Makefile.am | 6 +++--- src/bin/msgq/Makefile.am | 6 +++--- src/bin/resolver/Makefile.am | 6 +++--- src/bin/showtech/Makefile.am | 6 +++--- src/bin/sockcreator/Makefile.am | 6 +++--- src/bin/stats/Makefile.am | 6 +++--- src/bin/usermgr/Makefile.am | 6 +++--- src/bin/xfrin/Makefile.am | 6 +++--- src/bin/xfrout/Makefile.am | 6 +++--- src/bin/zonemgr/Makefile.am | 6 +++--- 22 files changed, 71 insertions(+), 71 deletions(-) diff --git a/configure.ac b/configure.ac index 6b3824f1b3..ba2958223e 100644 --- a/configure.ac +++ b/configure.ac @@ -1016,15 +1016,15 @@ AC_SUBST(PERL) AC_PATH_PROGS(AWK, gawk awk) AC_SUBST(AWK) -AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man], - [regenerate man pages using Docbook [default=no]])], - enable_man=$enableval, enable_man=no) +AC_ARG_ENABLE(generate_docs, [AC_HELP_STRING([--enable-generate-docs], + [regenerate documentation using Docbook [default=no]])], + enable_generate_docs=$enableval, enable_generate_docs=no) # Check for xsltproc -if test "x$enable_man" != xno ; then +if test "x$enable_generate_docs" != xno ; then AC_PATH_PROG([XSLTPROC], [xsltproc]) if test -z "$XSLTPROC"; then - AC_MSG_ERROR("xsltproc not found; it is required for --enable-man") + AC_MSG_ERROR("xsltproc not found; it is required for --enable-generate-docs") else AC_MSG_CHECKING([if $XSLTPROC works]) # run xsltproc to see if works @@ -1041,7 +1041,7 @@ if test "x$enable_man" != xno ; then fi -AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno) +AM_CONDITIONAL(GENERATE_DOCS, test x$enable_generate_docs != xno) AC_ARG_ENABLE(install-configurations, [AC_HELP_STRING([--disable-install-configurations], @@ -1385,7 +1385,7 @@ Developer: C++ Code Coverage: $USE_LCOV Python Code Coverage: $USE_PYCOVERAGE Logger checks: $enable_logger_checks - Generate Manuals: $enable_man + Generate Documentation: $enable_generate_docs END diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index 79d5d33ba8..36b12bc107 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = bind10-guide.xml CLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml # This is not a "man" manual, but reuse this for now for docbook. -if ENABLE_MAN +if GENERATE_DOCS bind10-guide.html: bind10-guide.xml @XSLTPROC@ --novalid --xinclude --nonet \ @@ -40,7 +40,7 @@ bind10-messages.xml: else $(HTMLDOCS) $(DOCS): - @echo Doc generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Doc generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Doc generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Doc generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index eb5b8efe48..5f2b3e6634 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -23,7 +23,7 @@ man_MANS = b10-auth.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-auth.xml -if ENABLE_MAN +if GENERATE_DOCS b10-auth.8: b10-auth.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-auth.xml @@ -31,8 +31,8 @@ b10-auth.8: b10-auth.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am index 68940c9dab..10f9918016 100644 --- a/src/bin/bind10/Makefile.am +++ b/src/bin/bind10/Makefile.am @@ -20,7 +20,7 @@ man_MANS = bind10.8 CLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) bind10.xml bind10_messages.mes -if ENABLE_MAN +if GENERATE_DOCS bind10.8: bind10.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bind10.xml @@ -31,11 +31,11 @@ bind10.8: bind10.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ #dist-local-check-mans-enabled: -# @echo "*** --enable-man must be used in order to make dist" +# @echo "*** --enable-generate-docs must be used in order to make dist" # @false endif diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am index 1e41345a30..a4c6dddadd 100644 --- a/src/bin/bindctl/Makefile.am +++ b/src/bin/bindctl/Makefile.am @@ -16,7 +16,7 @@ bindctldir = $(pkgdatadir) CLEANFILES = bindctl bindctl_main.pyc CLEANFILES += $(man_MANS) -if ENABLE_MAN +if GENERATE_DOCS bindctl.1: bindctl.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/bindctl.xml @@ -24,8 +24,8 @@ bindctl.1: bindctl.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am index 99feed564e..4c511ee97a 100644 --- a/src/bin/cfgmgr/Makefile.am +++ b/src/bin/cfgmgr/Makefile.am @@ -13,7 +13,7 @@ man_MANS = b10-cfgmgr.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cfgmgr.xml -if ENABLE_MAN +if GENERATE_DOCS b10-cfgmgr.8: b10-cfgmgr.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cfgmgr.xml @@ -21,8 +21,8 @@ b10-cfgmgr.8: b10-cfgmgr.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am index e6a8d5eeb5..7b2c21e70b 100644 --- a/src/bin/cmdctl/Makefile.am +++ b/src/bin/cmdctl/Makefile.am @@ -29,7 +29,7 @@ man_MANS = b10-cmdctl.8 CLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes -if ENABLE_MAN +if GENERATE_DOCS b10-cmdctl.8: b10-cmdctl.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml @@ -37,8 +37,8 @@ b10-cmdctl.8: b10-cmdctl.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/dbutil/Makefile.am b/src/bin/dbutil/Makefile.am index c15bdecb97..701ee799f3 100644 --- a/src/bin/dbutil/Makefile.am +++ b/src/bin/dbutil/Makefile.am @@ -16,7 +16,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyo CLEANFILES += $(man_MANS) -if ENABLE_MAN +if GENERATE_DOCS b10-dbutil.8: b10-dbutil.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-dbutil.xml @@ -24,8 +24,8 @@ b10-dbutil.8: b10-dbutil.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/ddns/Makefile.am b/src/bin/ddns/Makefile.am index 2f99e81af3..c9570bd7cf 100644 --- a/src/bin/ddns/Makefile.am +++ b/src/bin/ddns/Makefile.am @@ -20,7 +20,7 @@ man_MANS = b10-ddns.8 CLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) b10-ddns.xml -if ENABLE_MAN +if GENERATE_DOCS b10-ddns.8: b10-ddns.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-ddns.xml @@ -28,8 +28,8 @@ b10-ddns.8: b10-ddns.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index ad5f461445..f5f94c84c7 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -18,7 +18,7 @@ man_MANS = b10-dhcp4.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec -if ENABLE_MAN +if GENERATE_DOCS b10-dhcp4.8: b10-dhcp4.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ \ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \ @@ -27,8 +27,8 @@ b10-dhcp4.8: b10-dhcp4.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 43e109d621..433218c51d 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -19,7 +19,7 @@ man_MANS = b10-dhcp6.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec -if ENABLE_MAN +if GENERATE_DOCS b10-dhcp6.8: b10-dhcp6.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ \ @@ -29,8 +29,8 @@ b10-dhcp6.8: b10-dhcp6.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am index e64ac933eb..6d1bd04c15 100644 --- a/src/bin/host/Makefile.am +++ b/src/bin/host/Makefile.am @@ -21,7 +21,7 @@ CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-host.xml .PHONY: man -if ENABLE_MAN +if GENERATE_DOCS man: b10-host.1 @@ -31,7 +31,7 @@ b10-host.1: b10-host.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/loadzone/Makefile.am b/src/bin/loadzone/Makefile.am index 175a67a10e..74bd1df1d6 100644 --- a/src/bin/loadzone/Makefile.am +++ b/src/bin/loadzone/Makefile.am @@ -8,7 +8,7 @@ man_MANS = b10-loadzone.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-loadzone.xml -if ENABLE_MAN +if GENERATE_DOCS b10-loadzone.8: b10-loadzone.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-loadzone.xml @@ -16,8 +16,8 @@ b10-loadzone.8: b10-loadzone.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am index 25b0dc7b90..ef297e18c6 100644 --- a/src/bin/msgq/Makefile.am +++ b/src/bin/msgq/Makefile.am @@ -10,7 +10,7 @@ man_MANS = b10-msgq.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) msgq.xml -if ENABLE_MAN +if GENERATE_DOCS b10-msgq.8: msgq.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/msgq.xml @@ -18,8 +18,8 @@ b10-msgq.8: msgq.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index 3bb0d3c030..9d65418483 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -26,7 +26,7 @@ man_MANS = b10-resolver.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-resolver.xml resolver_messages.mes -if ENABLE_MAN +if GENERATE_DOCS b10-resolver.8: b10-resolver.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-resolver.xml @@ -34,8 +34,8 @@ b10-resolver.8: b10-resolver.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/showtech/Makefile.am b/src/bin/showtech/Makefile.am index 8ee078e903..a9fb6a5f8d 100644 --- a/src/bin/showtech/Makefile.am +++ b/src/bin/showtech/Makefile.am @@ -14,7 +14,7 @@ man_MANS = \ $(MAN1_FILES:.xml=.1) CLEANFILES += $(man_MANS) -if ENABLE_MAN +if GENERATE_DOCS .xml.1: @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< @@ -22,8 +22,8 @@ if ENABLE_MAN else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index a57f4aa814..3b0b15321e 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -16,7 +16,7 @@ man_MANS = b10-sockcreator.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-sockcreator.xml -if ENABLE_MAN +if GENERATE_DOCS b10-sockcreator.8: b10-sockcreator.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-sockcreator.xml @@ -24,8 +24,8 @@ b10-sockcreator.8: b10-sockcreator.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am index 88592e6b02..c4acfc8762 100644 --- a/src/bin/stats/Makefile.am +++ b/src/bin/stats/Makefile.am @@ -26,7 +26,7 @@ EXTRA_DIST += stats.spec stats-httpd.spec EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl EXTRA_DIST += stats_messages.mes stats_httpd_messages.mes -if ENABLE_MAN +if GENERATE_DOCS b10-stats.8: b10-stats.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml @@ -37,8 +37,8 @@ b10-stats-httpd.8: b10-stats-httpd.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am index 68bf3e596e..9d7a7c527c 100644 --- a/src/bin/usermgr/Makefile.am +++ b/src/bin/usermgr/Makefile.am @@ -8,7 +8,7 @@ man_MANS = b10-cmdctl-usermgr.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cmdctl-usermgr.xml -if ENABLE_MAN +if GENERATE_DOCS b10-cmdctl-usermgr.8: b10-cmdctl-usermgr.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl-usermgr.xml @@ -16,8 +16,8 @@ b10-cmdctl-usermgr.8: b10-cmdctl-usermgr.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am index b9434db46a..eb2d0b9c1d 100644 --- a/src/bin/xfrin/Makefile.am +++ b/src/bin/xfrin/Makefile.am @@ -19,7 +19,7 @@ CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrin.xml EXTRA_DIST += xfrin.spec xfrin_messages.mes -if ENABLE_MAN +if GENERATE_DOCS b10-xfrin.8: b10-xfrin.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrin.xml @@ -27,8 +27,8 @@ b10-xfrin.8: b10-xfrin.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am index c07f0693c6..9f8009e29c 100644 --- a/src/bin/xfrout/Makefile.am +++ b/src/bin/xfrout/Makefile.am @@ -18,7 +18,7 @@ man_MANS = b10-xfrout.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrout.xml xfrout_messages.mes -if ENABLE_MAN +if GENERATE_DOCS b10-xfrout.8: b10-xfrout.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-xfrout.xml @@ -26,8 +26,8 @@ b10-xfrout.8: b10-xfrout.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am index 7956326d49..9fbdaeb8f2 100644 --- a/src/bin/zonemgr/Makefile.am +++ b/src/bin/zonemgr/Makefile.am @@ -18,7 +18,7 @@ man_MANS = b10-zonemgr.8 CLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-zonemgr.xml zonemgr_messages.mes -if ENABLE_MAN +if GENERATE_DOCS b10-zonemgr.8: b10-zonemgr.xml @XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-zonemgr.xml @@ -26,8 +26,8 @@ b10-zonemgr.8: b10-zonemgr.xml else $(man_MANS): - @echo Man generation disabled. Creating dummy $@. Configure with --enable-man to enable it. - @echo Man generation disabled. Remove this file, configure with --enable-man, and rebuild BIND 10 > $@ + @echo Man generation disabled. Creating dummy $@. Configure with --enable-generate-docs to enable it. + @echo Man generation disabled. Remove this file, configure with --enable-generate-docs, and rebuild BIND 10 > $@ endif From 4ae9b5ea7462f0d2a7c87c8b3466ca100a310c74 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 3 Aug 2012 12:46:21 +0200 Subject: [PATCH 027/148] [1959] Moved sockets_ member in IfaceMgr to protected scope. --- src/lib/dhcp/iface_mgr.cc | 46 ++++++++++++++++++++++----------------- src/lib/dhcp/iface_mgr.h | 21 +++++++++++++++--- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index ae975d0820..99a3108e9a 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -66,6 +66,16 @@ IfaceMgr::Iface::Iface(const std::string& name, int ifindex) memset(mac_, 0, sizeof(mac_)); } +void +IfaceMgr::Iface::closeSockets() { + for (SocketCollection::iterator sock = sockets_.begin(); + sock != sockets_.end(); ++sock) { + cout << "Closing socket " << sock->sockfd_ << endl; + close(sock->sockfd_); + } + sockets_.clear(); +} + std::string IfaceMgr::Iface::getFullName() const { ostringstream tmp; @@ -154,15 +164,8 @@ IfaceMgr::IfaceMgr() void IfaceMgr::closeSockets() { for (IfaceCollection::iterator iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) { - - for (SocketCollection::iterator sock = iface->sockets_.begin(); - sock != iface->sockets_.end(); ++sock) { - cout << "Closing socket " << sock->sockfd_ << endl; - close(sock->sockfd_); - } - iface->sockets_.clear(); + iface->closeSockets(); } - } IfaceMgr::~IfaceMgr() { @@ -561,8 +564,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) { struct sockaddr_in6 addr6; memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; - addr6.sin6_port = htons(port); - if (addr.toText() != "::1") + addr6.sin6_port = htons(port); if (addr.toText() != "::1") addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str()); memcpy(&addr6.sin6_addr, @@ -740,7 +742,6 @@ IfaceMgr::send(const Pkt6Ptr& pkt) { bool IfaceMgr::send(const Pkt4Ptr& pkt) { - Iface* iface = getIface(pkt->getIface()); if (!iface) { isc_throw(BadValue, "Unable to send Pkt4. Invalid interface (" @@ -817,8 +818,9 @@ IfaceMgr::receive4(uint32_t timeout) { /// provided set to indicated which sockets have something to read. for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) { - for (SocketCollection::const_iterator s = iface->sockets_.begin(); - s != iface->sockets_.end(); ++s) { + const SocketCollection& socket_collection = iface->getSockets(); + for (SocketCollection::const_iterator s = socket_collection.begin(); + s != socket_collection.end(); ++s) { // Only deal with IPv4 addresses. if (s->addr_.getFamily() == AF_INET) { @@ -881,8 +883,9 @@ IfaceMgr::receive4(uint32_t timeout) { // Let's find out which interface/socket has the data for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) { - for (SocketCollection::const_iterator s = iface->sockets_.begin(); - s != iface->sockets_.end(); ++s) { + const SocketCollection& socket_collection = iface->getSockets(); + for (SocketCollection::const_iterator s = socket_collection.begin(); + s != socket_collection.end(); ++s) { if (FD_ISSET(s->sockfd_, &sockets)) { candidate = &(*s); break; @@ -1010,8 +1013,9 @@ Pkt6Ptr IfaceMgr::receive6() { IfaceCollection::const_iterator iface = ifaces_.begin(); const SocketInfo* candidate = 0; while (iface != ifaces_.end()) { - for (SocketCollection::const_iterator s = iface->sockets_.begin(); - s != iface->sockets_.end(); ++s) { + const SocketCollection& socket_collection = iface->getSockets(); + for (SocketCollection::const_iterator s = socket_collection.begin(); + s != socket_collection.end(); ++s) { if (s->addr_.getFamily() != AF_INET6) { continue; } @@ -1122,11 +1126,12 @@ uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) { << pkt.getIface()); } + const SocketCollection& socket_collection = iface->getSockets(); SocketCollection::const_iterator s; - for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) { + for (s = socket_collection.begin(); s != socket_collection.end(); ++s) { if ((s->family_ == AF_INET6) && (!s->addr_.getAddress().to_v6().is_multicast())) { - return (s->sockfd_); + return (s->sockfd_);t } /// @todo: Add more checks here later. If remote address is /// not link-local, we can't use link local bound socket @@ -1144,8 +1149,9 @@ uint16_t IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) { << pkt.getIface()); } + const SocketCollection& socket_collection = iface->getSockets(); SocketCollection::const_iterator s; - for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) { + for (s = socket_collection.begin(); s != socket_collection.end(); ++s) { if (s->family_ == AF_INET) { return (s->sockfd_); } diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index a40f95c69d..4a2016c89b 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -89,6 +89,9 @@ public: /// @param ifindex interface index (unique integer identifier) Iface(const std::string& name, int ifindex); + /// @brief Closes all open sockets on interface + void closeSockets(); + /// @brief Returns full interface name as "ifname/ifindex" string. /// /// @return string with interface name @@ -192,11 +195,23 @@ public: /// @return true if there was such socket, false otherwise bool delSocket(uint16_t sockfd); - /// socket used to sending data - /// TODO: this should be protected - SocketCollection sockets_; + /// @brief Returns collection of all sockets added to interface. + /// + /// When new socket is created with @ref IfaceMgr::openSocket + /// it is added to sockets collection on particular interface. + /// If socket is opened by other means (e.g. function that does + /// not use @ref IfaceMgr::openSocket) it will not be available + /// in this collection. Note that functions like + /// @ref IfaceMgr::openSocketFromIface use + /// @ref IfaceMgr::openSocket internally. + /// + /// @return collection of sockets added to interface + const SocketCollection& getSockets() const { return sockets_; } protected: + /// socket used to sending data + SocketCollection sockets_; + /// network interface name std::string name_; From 1127bca7125f7fb94fe3340a86e086307f80a9e2 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 3 Aug 2012 13:49:41 +0100 Subject: [PATCH 028/148] [1959] Implemented DHCPDISCOVER packet sending. --- tests/tools/perfdhcp/test_control.cc | 164 ++++++++++++++++-- tests/tools/perfdhcp/test_control.h | 35 +++- .../perfdhcp/tests/test_control_unittest.cc | 2 +- 3 files changed, 182 insertions(+), 19 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 8072e75461..de9aa1d727 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -19,9 +19,11 @@ #include -#include -#include #include +#include +#include +#include +#include #include "test_control.h" #include "command_options.h" @@ -30,10 +32,43 @@ using namespace boost; using namespace boost::posix_time; using namespace isc; using namespace isc::dhcp; +using namespace isc::asiolink; namespace isc { namespace perfdhcp { +TestControl::TestControlSocket::TestControlSocket(int socket) : + socket_(socket) { + initInterface(); +} + +TestControl::TestControlSocket::~TestControlSocket() { + IfaceMgr::instance().closeSockets(); +} + +void +TestControl::TestControlSocket::initInterface() { + const IfaceMgr::IfaceCollection& ifaces = + IfaceMgr::instance().getIfaces(); + for (IfaceMgr::IfaceCollection::const_iterator it = ifaces.begin(); + it != ifaces.end(); + ++it) { + const IfaceMgr::SocketCollection& socket_collection = + it->getSockets(); + for (IfaceMgr::SocketCollection::const_iterator s = + socket_collection.begin(); + s != socket_collection.end(); + ++s) { + if (s->sockfd_ == socket_) { + iface_ = it->getName(); + return; + } + } + } + isc_throw(BadValue, "interface for for specified socket " + "descriptor not found"); +} + TestControl& TestControl::instance() { static TestControl test_control; @@ -59,24 +94,37 @@ TestControl::checkExitConditions() const { } boost::shared_ptr -TestControl::createDiscoverPkt4() const { +TestControl::createDiscoverPkt4(const std::vector& mac_addr) const { const uint32_t transid = static_cast(random()); boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); if (!pkt4) { isc_throw(isc::Unexpected, "failed to create DISCOVER packet"); } - OptionPtr request_list_option = - Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST); - pkt4->addOption(request_list_option); + if (HW_ETHER_LEN != mac_addr.size()) { + isc_throw(BadValue, "invalid MAC address size"); + } + pkt4->setHWAddr(HTYPE_ETHER, HW_ETHER_LEN, mac_addr); + + OptionBuffer buf_msg_type; + buf_msg_type.push_back(DHCPDISCOVER); + pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, buf_msg_type)); + pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST)); return pkt4; } +OptionPtr +TestControl::factoryGeneric4(Option::Universe u, + uint16_t type, + const OptionBuffer& buf) { + OptionPtr opt(new Option(u, type, buf)); + return opt; +} + OptionPtr TestControl::factoryRequestList4(Option::Universe u, uint16_t type, - const OptionBuffer& buf) -{ + const OptionBuffer& buf) { const uint8_t buf_array[] = { DHO_SUBNET_MASK, DHO_BROADCAST_ADDRESS, @@ -88,9 +136,26 @@ TestControl::factoryRequestList4(Option::Universe u, }; OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); - Option* opt = new Option(u, type, buf); + OptionPtr opt(new Option(u, type, buf)); opt->setData(buf_with_options.begin(), buf_with_options.end()); - return OptionPtr(opt); + return opt; +} + +const std::vector& +TestControl::generateMacAddress() { + CommandOptions& options = CommandOptions::instance(); + uint32_t clients_num = options.getClientsNum(); + if ((clients_num == 0) || (clients_num == 1)) { + return last_mac_address_; + } + for (std::vector::iterator it = last_mac_address_.end() - 1; + it >= last_mac_address_.begin(); + --it) { + if (++(*it) > 0) { + break; + } + } + return last_mac_address_; } uint64_t @@ -141,10 +206,57 @@ TestControl::getNextExchangesNum() const { return (0); } +int +TestControl::openSocket() const { + CommandOptions& options = CommandOptions::instance(); + std::string localname = options.getLocalName(); + std::string servername = options.getServerName(); + uint8_t family = AF_INET; + uint16_t port = 67; + int sock = 0; + if (options.getIpVersion() == 6) { + family = AF_INET6; + port = 547; + } + if (!localname.empty()) { + bool is_interface = false;; + try { + sock = IfaceMgr::instance().openSocketFromIface(localname, + port, + family); + is_interface = true; + } catch (...) { + // This is not fatal error. It may be the case that + // parameter given from command line is not interface + // name but local IP address. + } + if (!is_interface) { + IOAddress localaddr(localname); + // We don't catch exception here because parameter given + // must be either interface name or local address. If + // both attempts failed, we want exception to be emited. + sock = IfaceMgr::instance().openSocketFromAddress(localaddr, + port); + } + } else if (!servername.empty()) { + IOAddress remoteaddr(servername); + sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr, + port); + } + if (sock <= 0) { + isc_throw(BadValue, "unable to open socket to communicate with " + "DHCP server"); + } + return sock; +} + void TestControl::registerOptionFactories4() const { static bool factories_registered = false; if (!factories_registered) { + LibDHCP::OptionFactoryRegister(Option::V4, + DHO_DHCP_MESSAGE_TYPE, + &TestControl::factoryGeneric4); LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST, &TestControl::factoryRequestList4); @@ -176,20 +288,32 @@ TestControl::registerOptionFactories() const { } } +void +TestControl::resetMacAddress() { + CommandOptions& options = CommandOptions::instance(); + std::vector mac_prefix(options.getMacPrefix()); + if (mac_prefix.size() != HW_ETHER_LEN) { + isc_throw(Unexpected, "MAC address prefix is invalid"); + } + std::swap(mac_prefix, last_mac_address_); +} + void TestControl::run() { sent_packets_0_ = 0; sent_packets_1_ = 0; CommandOptions& options = CommandOptions::instance(); // Ip version is not set ONLY in case the command options - // where not parsed. This surely means that parse() function + // were not parsed. This surely means that parse() function // was not called prior to starting the test. This is fatal // error. if (options.getIpVersion() == 0) { - isc_throw(InvalidOperation, "command options must be parsed before running " - "a test"); + isc_throw(InvalidOperation, + "command options must be parsed before running a test"); } registerOptionFactories(); + TestControlSocket socket(openSocket()); + resetMacAddress(); uint64_t packets_sent = 0; for (;;) { updateSendDue(); @@ -198,18 +322,26 @@ TestControl::run() { } uint64_t packets_due = getNextExchangesNum(); for (uint64_t i = packets_due; i > 0; --i) { - startExchange(); + startExchange(socket); ++packets_sent; cout << "Packets sent " << packets_sent << endl; } } - } void -TestControl::startExchange() { +TestControl::startExchange(const TestControlSocket& socket) { ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); + std::vector mac_address = generateMacAddress(); + boost::shared_ptr pkt4 = createDiscoverPkt4(mac_address); + pkt4->setIface(socket.getIface()); + try { + pkt4->pack(); + IfaceMgr::instance().send(pkt4); + } catch (const Exception& e) { + std::cout << e.what() << std::endl; + } } void diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index ce5aa4c4b6..676be013c7 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -33,6 +33,24 @@ namespace perfdhcp { /// class TestControl : public boost::noncopyable { public: + + class TestControlSocket { + public: + + TestControlSocket(const int socket); + ~TestControlSocket(); + + const std::string& getIface() const { return(iface_); } + + private: + void initInterface(); + + int socket_; + std::string iface_; + }; + + static const uint8_t HW_ETHER_LEN = 6; + /// TestControl is a singleton class. This method returns reference /// to its sole instance. /// @@ -69,12 +87,19 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; - boost::shared_ptr createDiscoverPkt4() const; + boost::shared_ptr + createDiscoverPkt4(const std::vector& mac_addr) const; + + static dhcp::OptionPtr factoryGeneric4(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); + const std::vector& generateMacAddress(); + /// \brief Returns number of exchanges to be started. /// /// Method returns number of new exchanges to be started as soon @@ -85,15 +110,19 @@ private: /// \return number of exchanges to be started immediatelly. uint64_t getNextExchangesNum() const; + int openSocket() const; + void registerOptionFactories4() const; void registerOptionFactories6() const; void registerOptionFactories() const; + void resetMacAddress(); + /// \brief Start new exchange of DHCP messages. /// - void startExchange(); + void startExchange(const TestControlSocket& socket); /// \brief Update due time to initiate next chunk of exchanges. /// @@ -107,6 +136,8 @@ private: boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange /// was initiated. + std::vector last_mac_address_;/// Least generated MAC address. + uint64_t sent_packets_0_; uint64_t sent_packets_1_; }; diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 7a66b03fb3..2cc6b93f53 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -48,7 +48,7 @@ TEST_F(TestControlTest, Run) { // The command line is to run single test iteration and exit. // We have to declare argv as const walk around the problem // of deprecated conversion from string to char*. - const char* argv[] = { "perfdhcp", "-l", "eth0", "-r", "10", "-n", "1" }; + const char* argv[] = { "perfdhcp", "-l", "127.0.0.1", "-r", "10", "-n", "1" }; const int argc = sizeof(argv) / sizeof(argv[0]); CommandOptions& options = CommandOptions::instance(); From ca2a79864dbc56af29eb95e01141fa86b2be8b44 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 3 Aug 2012 16:56:48 +0100 Subject: [PATCH 029/148] [1959] Documentation cleanup. --- tests/tools/perfdhcp/test_control.cc | 40 +++---- tests/tools/perfdhcp/test_control.h | 157 +++++++++++++++++++++++++-- 2 files changed, 162 insertions(+), 35 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index de9aa1d727..ef47be6e5a 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -141,21 +141,26 @@ TestControl::factoryRequestList4(Option::Universe u, return opt; } -const std::vector& -TestControl::generateMacAddress() { +std::vector +TestControl::generateMacAddress() const { CommandOptions& options = CommandOptions::instance(); uint32_t clients_num = options.getClientsNum(); if ((clients_num == 0) || (clients_num == 1)) { - return last_mac_address_; + return options.getMacPrefix(); } - for (std::vector::iterator it = last_mac_address_.end() - 1; - it >= last_mac_address_.begin(); + std::vector mac_addr(options.getMacPrefix()); + uint32_t r = random(); + r %= clients_num + 1; + for (std::vector::iterator it = mac_addr.end() - 1; + it >= mac_addr.begin(); --it) { - if (++(*it) > 0) { + (*it) += r; + if (r < 256) { break; } + r >>= 8; } - return last_mac_address_; + return mac_addr; } uint64_t @@ -165,7 +170,7 @@ TestControl::getNextExchangesNum() const { uint64_t due_exchanges = 0; // Get current time. ptime now(microsec_clock::universal_time()); - // The due time indicates when we should start sening next chunk + // The due time indicates when we should start sending next chunk // of packets. If it is already due time, we should calculate // how many packets to send. if (now >= send_due_) { @@ -288,16 +293,6 @@ TestControl::registerOptionFactories() const { } } -void -TestControl::resetMacAddress() { - CommandOptions& options = CommandOptions::instance(); - std::vector mac_prefix(options.getMacPrefix()); - if (mac_prefix.size() != HW_ETHER_LEN) { - isc_throw(Unexpected, "MAC address prefix is invalid"); - } - std::swap(mac_prefix, last_mac_address_); -} - void TestControl::run() { sent_packets_0_ = 0; @@ -313,7 +308,6 @@ TestControl::run() { } registerOptionFactories(); TestControlSocket socket(openSocket()); - resetMacAddress(); uint64_t packets_sent = 0; for (;;) { updateSendDue(); @@ -336,12 +330,8 @@ TestControl::startExchange(const TestControlSocket& socket) { std::vector mac_address = generateMacAddress(); boost::shared_ptr pkt4 = createDiscoverPkt4(mac_address); pkt4->setIface(socket.getIface()); - try { - pkt4->pack(); - IfaceMgr::instance().send(pkt4); - } catch (const Exception& e) { - std::cout << e.what() << std::endl; - } + pkt4->pack(); + IfaceMgr::instance().send(pkt4); } void diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 676be013c7..36280f2462 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -29,26 +29,66 @@ namespace perfdhcp { /// \brief Test Control class. /// -/// This class is responsible for running whole perfdhcp test. +/// This class is responsible for executing DHCP performance +/// test end to end. /// class TestControl : public boost::noncopyable { public: + /// \brief Socket wrapper class. + /// + /// This is wrapper class that holds descriptor of the socket + /// used to run DHCP test. All sockets created with \ref IfaceMgr + /// are closed in the destructor. This ensures that socket is + /// closed when the function that created the socket ends + /// (normally or when exception occurs). class TestControlSocket { public: + /// \brief Constructor of socket wrapper class. + /// + /// This constructor uses provided socket descriptor to + /// find the name of the interface where socket has been + /// bound to. + /// + /// \param socket socket descriptor. + /// \throw isc::BadValue if interface for specified + /// socket descriptor does not exist. TestControlSocket(const int socket); + + /// \brief Destriuctor of the socket wrapper class. + /// + /// Destructor closes all open sockets on all interfaces. + /// TODO: close only the socket being wrapped by this class. ~TestControlSocket(); + /// \brief Return name of the interface where socket is bound to. + /// + /// \return name of the interface where socket is bound to. const std::string& getIface() const { return(iface_); } private: + /// \brief Private default constructor. + /// + /// Default constructor is private to make sure that valid + /// socket descriptor is passed to create object. + TestControlSocket(); + + /// \brief Initialize name of the interface. + /// + /// This method intializes the name of the interface where + /// socket is bound to. This name can be later retreived by + /// client class to set interface name in DHCP packet objects. + /// + /// \throw isc::BadValue if interface for specified socket + /// descriptor does not exist. void initInterface(); - int socket_; - std::string iface_; + int socket_; ///< Socket descirptor. + std::string iface_; ///< Name of the interface. }; + /// \brief Length of the Ethernet HW address (MAC) in bytes. static const uint8_t HW_ETHER_LEN = 6; /// TestControl is a singleton class. This method returns reference @@ -87,18 +127,86 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; + /// \brief Create DHCPv4 DISCOVER packet. + /// + /// Create instance of DHCPv4 DISCOVER packet with ethernet + /// HW type and MAC address specified as parameter. The following + /// DHCP options are added to the packet: + /// - DHO_DHCP_MESSAGE_TYPE with DHCPDISCOVER message type value + /// - DHO_DHCP_PARAMETER_REQUEST_LIST with the following options + /// being requested from the server: + /// - DHO_SUBNET_MASK, + /// - DHO_BROADCAST_ADDRESS, + /// - DHO_TIME_OFFSET, + /// - DHO_ROUTERS, + /// - DHO_DOMAIN_NAME, + /// - DHO_DOMAIN_NAME_SERVERS, + /// - DHO_HOST_NAME. + /// + /// \param mac_addr MAC address to be set for the packet. MAC address + /// has to be exactly 6 octets long. + /// \throw isc::Unexpected if failed to create new packet instance. + /// \throw isc::BadValue if MAC address has invalid length. + /// \return insance of the DHCPv4 DISCOVER packet. boost::shared_ptr createDiscoverPkt4(const std::vector& mac_addr) const; + /// \brief Factory function to create generic option. + /// + /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister. + /// Registered factory functions provide a way to create options of the + /// same type in the same way. When new option instance is needed the + /// corresponding factory function is called to create it. This is done + /// by calling \ref Option::factory with DHCP message type specified as + /// one of parameters. Some of the parameters passed to factory function + /// may be ignored (e.g. option buffer). For generic option however, factory + /// function creates option using contents of the buffer. + /// + /// \param u universe (V6 or V4). + /// \param type option-type. + /// \param buf option-buffer. + /// \return instance o the generic option. static dhcp::OptionPtr factoryGeneric4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); - static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, + /// \brief Factory function to create DHCPv4 Request List option. + /// + /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister. + /// Registered factory functions provide a way to create options of the + /// same type in the same way. When new option instance is needed the + /// corresponding factory function is called to create it. This is done + /// by calling \ref Option::factory with DHCP message type specified as + /// one of parameters. This factory function ignores contents of the + /// buffer provided and creates option buffer internally with the following + /// list of requested options: + /// - DHO_SUBNET_MASK, + /// - DHO_BROADCAST_ADDRESS, + /// - DHO_TIME_OFFSET, + /// - DHO_ROUTERS, + /// - DHO_DOMAIN_NAME, + /// - DHO_DOMAIN_NAME_SERVERS, + /// - DHO_HOST_NAME. + /// + /// \param u universe (V6 or V4). + /// \param type option-type. + /// \param buf option-buffer. + /// \return instance o the generic option. + static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); - const std::vector& generateMacAddress(); + /// \brief Generate MAC address. + /// + /// This method generates MAC address. The number of unique + /// MAC addresses it can generate is determined by the number + /// simulated DHCP clients specified from command line. It uses + /// \ref CommandOptions object to retrieve number of clients. + /// Based on this the random value is generated and added to + /// the MAC address prefix (default MAC address). + /// + /// \return generated MAC address. + std::vector generateMacAddress() const; /// \brief Returns number of exchanges to be started. /// @@ -110,18 +218,49 @@ private: /// \return number of exchanges to be started immediatelly. uint64_t getNextExchangesNum() const; + /// \brief Open socket to communicate with DHCP server. + /// + /// Method opens socket and binds it to local address. Function will + /// can use either interface name, local address or server address + /// to create a socket, depending on what is available (specified + /// from the command line). If socket can't be created for any + /// reason, exception is thrown. + /// + /// \throw isc::BadValue if socket can't be created. + /// \return socket descriptor. int openSocket() const; + /// \brief Register option factory functions for DHCPv4 + /// + /// Method registers option factory functions for DHCPv4. + /// These functions are called to create instances of DHCPv4 + /// options. Call \ref Option::factory to invoke factory + /// function for particular option. Don't use this function directly. + /// Use \ref registerOptionFactories instead. void registerOptionFactories4() const; + /// \brief Register option factory functions for DHCPv6 + /// + /// Method registers option factory functions for DHCPv6. + /// These functions are called to create instances of DHCPv6 + /// options. Call \ref Option::factory to invoke factory + /// function for particular option. Don't use this function directly. + /// Use \ref registerOptionFactories instead. void registerOptionFactories6() const; - void registerOptionFactories() const; - - void resetMacAddress(); + /// \brief Register option factory functions for DHCPv4 or DHCPv6. + /// + /// Method registers option factory functions for DHCPv4 or DHCPv6, + /// depending in whch mode test is currently running. + void registerOptionFactories() const; /// \brief Start new exchange of DHCP messages. /// + /// Method starts new DHCP exchange by sending new DHCPv4 DISCOVER + /// or DHCPv6 SOLICIT packet to the server. + /// + /// \param socket socket used to send DHCP message. + /// \throw isc::Unexpected if failed to create or send packet void startExchange(const TestControlSocket& socket); /// \brief Update due time to initiate next chunk of exchanges. @@ -136,8 +275,6 @@ private: boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange /// was initiated. - std::vector last_mac_address_;/// Least generated MAC address. - uint64_t sent_packets_0_; uint64_t sent_packets_1_; }; From cc5e14f7a89e3d5fc6211d156d631aa37b865597 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Sat, 4 Aug 2012 10:41:46 +0100 Subject: [PATCH 030/148] [1959] Receive packets from the server. --- tests/tools/perfdhcp/test_control.cc | 19 ++++++++++++++++++- tests/tools/perfdhcp/test_control.h | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index ef47be6e5a..888a992700 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -252,7 +252,21 @@ TestControl::openSocket() const { isc_throw(BadValue, "unable to open socket to communicate with " "DHCP server"); } - return sock; + return(sock); +} + +void +TestControl::receivePackets() { + int timeout = 0; + bool receiving = true; + while (receiving) { + Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout); + if (!pkt4) { + receiving = false; + } else { + std::cout << "Received packet" << std::endl; + } + } } void @@ -315,6 +329,9 @@ TestControl::run() { break; } uint64_t packets_due = getNextExchangesNum(); + + receivePackets(); + for (uint64_t i = packets_due; i > 0; --i) { startExchange(socket); ++packets_sent; diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 36280f2462..cb1e641bbd 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -230,6 +230,8 @@ private: /// \return socket descriptor. int openSocket() const; + void receivePackets(); + /// \brief Register option factory functions for DHCPv4 /// /// Method registers option factory functions for DHCPv4. From 2e6923cefcd6582ccbf9ef859ff92a91665b90ef Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Mon, 6 Aug 2012 15:07:07 +0200 Subject: [PATCH 031/148] [1959] Set packet v4 defaults correctly --- tests/tools/perfdhcp/test_control.cc | 66 +++++++++++++---------- tests/tools/perfdhcp/test_control.h | 81 +++++++++++++++------------- 2 files changed, 80 insertions(+), 67 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 888a992700..6e793cd578 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -38,8 +38,9 @@ namespace isc { namespace perfdhcp { TestControl::TestControlSocket::TestControlSocket(int socket) : - socket_(socket) { - initInterface(); + socket_(socket), + addr_("127.0.0.1") { + initSocketData(); } TestControl::TestControlSocket::~TestControlSocket() { @@ -47,7 +48,7 @@ TestControl::TestControlSocket::~TestControlSocket() { } void -TestControl::TestControlSocket::initInterface() { +TestControl::TestControlSocket::initSocketData() { const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces(); for (IfaceMgr::IfaceCollection::const_iterator it = ifaces.begin(); @@ -61,6 +62,7 @@ TestControl::TestControlSocket::initInterface() { ++s) { if (s->sockfd_ == socket_) { iface_ = it->getName(); + addr_ = s->addr_; return; } } @@ -93,26 +95,6 @@ TestControl::checkExitConditions() const { return(false); } -boost::shared_ptr -TestControl::createDiscoverPkt4(const std::vector& mac_addr) const { - const uint32_t transid = static_cast(random()); - boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); - if (!pkt4) { - isc_throw(isc::Unexpected, "failed to create DISCOVER packet"); - } - - if (HW_ETHER_LEN != mac_addr.size()) { - isc_throw(BadValue, "invalid MAC address size"); - } - pkt4->setHWAddr(HTYPE_ETHER, HW_ETHER_LEN, mac_addr); - - OptionBuffer buf_msg_type; - buf_msg_type.push_back(DHCPDISCOVER); - pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, buf_msg_type)); - pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST)); - return pkt4; -} - OptionPtr TestControl::factoryGeneric4(Option::Universe u, uint16_t type, @@ -149,8 +131,11 @@ TestControl::generateMacAddress() const { return options.getMacPrefix(); } std::vector mac_addr(options.getMacPrefix()); + if (mac_addr.size() != HW_ETHER_LEN) { + isc_throw(BadValue, "invalid MAC address prefix specified"); + } uint32_t r = random(); - r %= clients_num + 1; + r %= clients_num; for (std::vector::iterator it = mac_addr.end() - 1; it >= mac_addr.begin(); --it) { @@ -333,7 +318,7 @@ TestControl::run() { receivePackets(); for (uint64_t i = packets_due; i > 0; --i) { - startExchange(socket); + sendDiscover4(socket); ++packets_sent; cout << "Packets sent " << packets_sent << endl; } @@ -341,20 +326,43 @@ TestControl::run() { } void -TestControl::startExchange(const TestControlSocket& socket) { +TestControl::sendDiscover4(const TestControlSocket& socket) { ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); std::vector mac_address = generateMacAddress(); - boost::shared_ptr pkt4 = createDiscoverPkt4(mac_address); - pkt4->setIface(socket.getIface()); + const uint32_t transid = static_cast(random()); + boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); + if (!pkt4) { + isc_throw(Unexpected, "failed to create DISCOVER packet"); + } + OptionBuffer buf_msg_type; + buf_msg_type.push_back(DHCPDISCOVER); + pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, + buf_msg_type)); + pkt4->addOption(Option::factory(Option::V4, + DHO_DHCP_PARAMETER_REQUEST_LIST)); + + setDefaults4(socket, pkt4); pkt4->pack(); IfaceMgr::instance().send(pkt4); } +void +TestControl::setDefaults4(const TestControlSocket &socket, + const boost::shared_ptr& pkt) { + CommandOptions& options = CommandOptions::instance(); + pkt->setIface(socket.getIface()); + pkt->setLocalPort(DHCP4_CLIENT_PORT); + pkt->setRemotePort(DHCP4_SERVER_PORT); + pkt->setRemoteAddr(IOAddress(options.getServerName())); + pkt->setGiaddr(IOAddress(socket.getAddress())); + pkt->setHops(1); +} + void TestControl::updateSendDue() { // If default constructor was called, this should not happen but - // if somebody has changed default constructor it is better to + // if somebody has cw/e August 3, 2012hanged default constructor it is better to // keep this check. if (last_sent_.is_not_a_date_time()) { isc_throw(Unexpected, "time of last sent packet not initialized"); diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index cb1e641bbd..8d6c4f3c81 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -67,6 +67,11 @@ public: /// \return name of the interface where socket is bound to. const std::string& getIface() const { return(iface_); } + /// \brief Return address where socket is bound to. + /// + /// \return address where socket is bound to. + const asiolink::IOAddress& getAddress() const { return(addr_); } + private: /// \brief Private default constructor. /// @@ -74,18 +79,18 @@ public: /// socket descriptor is passed to create object. TestControlSocket(); - /// \brief Initialize name of the interface. + /// \brief Initialize socket data. /// - /// This method intializes the name of the interface where - /// socket is bound to. This name can be later retreived by - /// client class to set interface name in DHCP packet objects. + /// This method initializes members of the class that Interface + /// Manager holds: interface name, local address. /// /// \throw isc::BadValue if interface for specified socket /// descriptor does not exist. - void initInterface(); + void initSocketData(); - int socket_; ///< Socket descirptor. - std::string iface_; ///< Name of the interface. + int socket_; ///< Socket descirptor. + std::string iface_; ///< Name of the interface. + asiolink::IOAddress addr_; ///< Address bound. }; /// \brief Length of the Ethernet HW address (MAC) in bytes. @@ -127,30 +132,6 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; - /// \brief Create DHCPv4 DISCOVER packet. - /// - /// Create instance of DHCPv4 DISCOVER packet with ethernet - /// HW type and MAC address specified as parameter. The following - /// DHCP options are added to the packet: - /// - DHO_DHCP_MESSAGE_TYPE with DHCPDISCOVER message type value - /// - DHO_DHCP_PARAMETER_REQUEST_LIST with the following options - /// being requested from the server: - /// - DHO_SUBNET_MASK, - /// - DHO_BROADCAST_ADDRESS, - /// - DHO_TIME_OFFSET, - /// - DHO_ROUTERS, - /// - DHO_DOMAIN_NAME, - /// - DHO_DOMAIN_NAME_SERVERS, - /// - DHO_HOST_NAME. - /// - /// \param mac_addr MAC address to be set for the packet. MAC address - /// has to be exactly 6 octets long. - /// \throw isc::Unexpected if failed to create new packet instance. - /// \throw isc::BadValue if MAC address has invalid length. - /// \return insance of the DHCPv4 DISCOVER packet. - boost::shared_ptr - createDiscoverPkt4(const std::vector& mac_addr) const; - /// \brief Factory function to create generic option. /// /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister. @@ -205,6 +186,8 @@ private: /// Based on this the random value is generated and added to /// the MAC address prefix (default MAC address). /// + /// \throw isc::BadValue if MAC address prefix (default or specified + /// from the command line) has invalid size (expected 6 octets). /// \return generated MAC address. std::vector generateMacAddress() const; @@ -254,16 +237,38 @@ private: /// /// Method registers option factory functions for DHCPv4 or DHCPv6, /// depending in whch mode test is currently running. - void registerOptionFactories() const; + void registerOptionFactories() const; - /// \brief Start new exchange of DHCP messages. + /// \brief Send DHCPv4 DISCOVER message. /// - /// Method starts new DHCP exchange by sending new DHCPv4 DISCOVER - /// or DHCPv6 SOLICIT packet to the server. + /// Method creates and sends DHCPv4 DISCOVER message to the server + /// with the following options: + /// - MESSAGE_TYPE set to DHCPDISCOVER + /// - PARAMETER_REQUEST_LIST with the same list of requested options + /// as described in \ref factoryRequestList. + /// The transaction id and MAC address are randomly generated for + /// the message. Range of unique MAC addresses generated depends + /// on the number of clients specified from the command line. /// - /// \param socket socket used to send DHCP message. - /// \throw isc::Unexpected if failed to create or send packet - void startExchange(const TestControlSocket& socket); + /// \param socket socket to be used to send the message. + /// \throw isc::Unexpected if failed to create new packet instance. + /// \throw isc::BadValue if MAC address has invalid length. + void sendDiscover4(const TestControlSocket &socket); + + /// \brief Set default DHCPv4 packet data. + /// + /// This method sets default data on the DHCPv4 packet: + /// - interface name, + /// - local port = 68 (DHCP client port), + /// - remote port = 67 (DHCP server port), + /// - server's address, + /// - GIADDR = local address where socket is bound to, + /// - hops = 1 (pretending that we are a relay) + /// + /// \param socket socket used to send the packet. + /// \param pkt packet to be configured. + void setDefaults4(const TestControlSocket& socket, + const boost::shared_ptr& pkt); /// \brief Update due time to initiate next chunk of exchanges. /// From e5fc094ff9c928e8f7761de883bfa0ad34cf86c2 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 7 Aug 2012 14:43:09 +0200 Subject: [PATCH 032/148] [1959] Enable use of broadcast remote address. --- src/lib/dhcp/iface_mgr.cc | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 99a3108e9a..335d848cd1 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -496,11 +496,28 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) { asio::io_service io_service; asio::ip::udp::socket sock(io_service); - // Try to connect to remote endpoint and check if attempt is successful. asio::error_code err_code; + // If remote address is broadcast address we have to + // allow this on the socket. + if (remote_addr.getAddress().is_v4() && + (remote_addr == IOAddress("255.255.255.255"))) { + // Socket has to be open prior to setting the broadcast + // option. Otherwise set_option will complain about + // bad file descriptor. + sock.open(asio::ip::udp::v4(), err_code); + if (err_code) { + isc_throw(Unexpected, "failed to open UDPv4 socket"); + } + sock.set_option(asio::socket_base::broadcast(true), err_code); + if (err_code) { + isc_throw(Unexpected, "failed to enable broadcast on the socket"); + } + } + + // Try to connect to remote endpoint and check if attempt is successful. sock.connect(remote_endpoint->getASIOEndpoint(), err_code); if (err_code) { - isc_throw(Unexpected,"Failed to connect to remote endpoint."); + isc_throw(Unexpected,"failed to connect to remote endpoint."); } // Once we are connected socket object holds local endpoint. @@ -1131,7 +1148,7 @@ uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) { for (s = socket_collection.begin(); s != socket_collection.end(); ++s) { if ((s->family_ == AF_INET6) && (!s->addr_.getAddress().to_v6().is_multicast())) { - return (s->sockfd_);t + return (s->sockfd_); } /// @todo: Add more checks here later. If remote address is /// not link-local, we can't use link local bound socket From 9dc528fb9ce46478f415722abfb9068d264154ce Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 7 Aug 2012 14:45:06 +0200 Subject: [PATCH 033/148] [1959] Enable broadcast addresses for perfdhcp's DHCPv4 mode. --- tests/tools/perfdhcp/command_options.cc | 32 +- tests/tools/perfdhcp/command_options.h | 7 + tests/tools/perfdhcp/test_control.cc | 37 ++- tests/tools/perfdhcp/test_control.h | 5 +- .../tests/command_options_unittest.cc | 284 ++++++++++++------ 5 files changed, 261 insertions(+), 104 deletions(-) diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index 09393bbc3d..55380d086b 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -21,8 +21,8 @@ #include #include -#include "exceptions/exceptions.h" - +#include +#include #include "command_options.h" using namespace std; @@ -219,6 +219,7 @@ CommandOptions::initialize(int argc, char** argv) { case 'l': localname_ = std::string(optarg); + initIsInterface(); break; case 'L': @@ -351,7 +352,21 @@ CommandOptions::initialize(int argc, char** argv) { } } - // TODO handle -l option with IfaceManager when it is created + // Handle the local '-l' address/interface + if (!localname_.empty()) { + if (server_name_.empty()) { + if (is_interface_ && (ipversion_ == 4)) { + broadcast_ = 1; + server_name_ = "255.255.255.255"; + } else if (is_interface_ && (ipversion_ == 6)) { + server_name_ = "FF02::1:2"; + } + } + } + if (server_name_.empty()) { + isc_throw(InvalidParameter, + "without an inteface server is required"); + } } void @@ -376,6 +391,17 @@ CommandOptions::initClientsNum() { } } +void +CommandOptions::initIsInterface() { + is_interface_ = false; + if (!localname_.empty()) { + dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance(); + if (iface_mgr.getIface(localname_) != NULL) { + is_interface_ = true; + } + } +} + void CommandOptions::decodeBase(const std::string& base) { std::string b(base); diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h index 9196857d7c..459efa598b 100644 --- a/tests/tools/perfdhcp/command_options.h +++ b/tests/tools/perfdhcp/command_options.h @@ -301,6 +301,13 @@ private: /// \throw InvalidParameter if -R is wrong void initClientsNum(); + /// \brief Sets value indicating if interface name was given. + /// + /// Method checks if the command line argument given with + /// '-l' option is the interface name. The is_interface_ member + /// is set accordingly. + void initIsInterface(); + /// \brief Decodes base provided with -b /// /// Function decodes argument of -b switch, which diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 6e793cd578..c050c9f0a6 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -208,27 +208,24 @@ TestControl::openSocket() const { family = AF_INET6; port = 547; } + // Local name is specified along with '-l' option. + // It may point to interface name or local address. if (!localname.empty()) { - bool is_interface = false;; - try { + // CommandOptions should be already aware wether local name + // is interface name or address because it uses IfaceMgr to + // scan interfaces and get's their names. + if (options.isInterface()) { sock = IfaceMgr::instance().openSocketFromIface(localname, port, family); - is_interface = true; - } catch (...) { - // This is not fatal error. It may be the case that - // parameter given from command line is not interface - // name but local IP address. - } - if (!is_interface) { + } else { IOAddress localaddr(localname); - // We don't catch exception here because parameter given - // must be either interface name or local address. If - // both attempts failed, we want exception to be emited. sock = IfaceMgr::instance().openSocketFromAddress(localaddr, port); } } else if (!servername.empty()) { + // If only server name is given we will need to try to resolve + // the local address to bind socket to based on remote address. IOAddress remoteaddr(servername); sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr, port); @@ -237,6 +234,20 @@ TestControl::openSocket() const { isc_throw(BadValue, "unable to open socket to communicate with " "DHCP server"); } + + // IfaceMgr does not set broadcast option on the socket. We rely + // on CommandOptions object to find out if socket has to have + // broadcast enabled. + if ((options.getIpVersion() == 4) && options.isBroadcast()) { + int broadcast_enable = 1; + int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, + &broadcast_enable, sizeof(broadcast_enable)); + if (ret < 0) { + isc_throw(InvalidOperation, + "unable to set broadcast option on the socket"); + } + } + return(sock); } @@ -362,7 +373,7 @@ TestControl::setDefaults4(const TestControlSocket &socket, void TestControl::updateSendDue() { // If default constructor was called, this should not happen but - // if somebody has cw/e August 3, 2012hanged default constructor it is better to + // if somebody has changed default constructor it is better to // keep this check. if (last_sent_.is_not_a_date_time()) { isc_throw(Unexpected, "time of last sent packet not initialized"); diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 8d6c4f3c81..bb1f283712 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -209,7 +209,10 @@ private: /// from the command line). If socket can't be created for any /// reason, exception is thrown. /// - /// \throw isc::BadValue if socket can't be created. + /// \throw isc::BadValue if socket can't be created for given + /// interface, local address or remote address. + /// \throw isc::InvalidOperation if broadcast option can't be + /// set for the socket. /// \return socket descriptor. int openSocket() const; diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index 8e1053dc30..669d792bb5 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -17,9 +17,10 @@ #include #include -#include "../command_options.h" +#include +#include -#include "exceptions/exceptions.h" +#include "../command_options.h" using namespace std; using namespace isc; @@ -62,7 +63,7 @@ protected: /// Check if initialized values are correct void checkDefaults() { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp"); + process("perfdhcp 192.168.0.1"); EXPECT_EQ(4, opt.getIpVersion()); EXPECT_EQ(CommandOptions::DORA_SARR, opt.getExchangeMode()); EXPECT_EQ(0, opt.getRate()); @@ -104,7 +105,7 @@ protected: EXPECT_GT(0, opt.getRequestedIpOffset()); EXPECT_EQ("", opt.getDiags()); EXPECT_EQ("", opt.getWrapped()); - EXPECT_EQ("", opt.getServerName()); + EXPECT_EQ("192.168.0.1", opt.getServerName()); } /// \brief Split string to array of C-strings @@ -145,79 +146,90 @@ protected: }; TEST_F(CommandOptionsTest, Defaults) { - process("perfdhcp"); + process("perfdhcp all"); checkDefaults(); } TEST_F(CommandOptionsTest, UseFirst) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -1 -B -l ethx"); + process("perfdhcp -1 -B -l ethx all"); EXPECT_TRUE(opt.isUseFirst()); } TEST_F(CommandOptionsTest, IpVersion) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -6 -l ethx -c -i"); + process("perfdhcp -6 -l ethx -c -i all"); EXPECT_EQ(6, opt.getIpVersion()); EXPECT_EQ("ethx", opt.getLocalName()); EXPECT_TRUE(opt.isRapidCommit()); EXPECT_FALSE(opt.isBroadcast()); - process("perfdhcp -4 -B -l ethx"); + process("perfdhcp -4 -B -l ethx all"); EXPECT_EQ(4, opt.getIpVersion()); EXPECT_TRUE(opt.isBroadcast()); EXPECT_FALSE(opt.isRapidCommit()); // Negative test cases // -4 and -6 must not coexist - EXPECT_THROW(process("perfdhcp -4 -6 -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -4 -6 -l ethx all"), isc::InvalidParameter); // -6 and -B must not coexist - EXPECT_THROW(process("perfdhcp -6 -B -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -B -l ethx all"), isc::InvalidParameter); // -c and -4 (default) must not coexist - EXPECT_THROW(process("perfdhcp -c -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -c -l ethx all"), isc::InvalidParameter); } TEST_F(CommandOptionsTest, Rate) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -4 -r 10 -l ethx"); + process("perfdhcp -4 -r 10 -l ethx all"); EXPECT_EQ(10, opt.getRate()); // Negative test cases // Rate must not be 0 - EXPECT_THROW(process("perfdhcp -4 -r 0 -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -4 -r 0 -l ethx all"), + isc::InvalidParameter); // -r must be specified to use -n, -p and -D - EXPECT_THROW(process("perfdhcp -6 -t 5 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -4 -n 150 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -6 -p 120 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -4 -D 1400 -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -t 5 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -4 -n 150 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -p 120 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -4 -D 1400 -l ethx all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, ReportDelay) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -r 100 -t 17 -l ethx"); + process("perfdhcp -r 100 -t 17 -l ethx all"); EXPECT_EQ(17, opt.getReportDelay()); // Negative test cases // -t must be positive integer - EXPECT_THROW(process("perfdhcp -r 10 -t -8 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -r 10 -t 0 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -r 10 -t s -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -r 10 -t -8 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -r 10 -t 0 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -r 10 -t s -l ethx all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, ClientsNum) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -R 200 -l ethx"); + process("perfdhcp -R 200 -l ethx all"); EXPECT_EQ(200, opt.getClientsNum()); - process("perfdhcp -R 0 -l ethx"); + process("perfdhcp -R 0 -l ethx all"); EXPECT_EQ(0, opt.getClientsNum()); // Negative test cases // Number of clients must be non-negative integer - EXPECT_THROW(process("perfdhcp -R -5 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -R gs -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -R -5 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -R gs -l ethx all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Base) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -6 -b MAC=10::20::30::40::50::60 -l ethx -b duiD=1AB7F5670901FF"); + process("perfdhcp -6 -b MAC=10::20::30::40::50::60 " + "-l ethx -b duiD=1AB7F5670901FF all"); uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 }; uint8_t duid[7] = { 0x1A, 0xB7, 0xF5, 0x67, 0x09, 0x01, 0xFF }; @@ -226,72 +238,87 @@ TEST_F(CommandOptionsTest, Base) { ASSERT_EQ(6, v1.size()); EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); // "3x" is invalid value in MAC address - EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"), + isc::InvalidParameter); // Test DUID std::vector v2 = opt.getDuidPrefix(); ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size()); EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); // "t" is invalid digit in DUID - EXPECT_THROW(process("perfdhcp -6 -l ethx -b duiD=1AB7Ft670901FF"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -l ethx -b duiD=1AB7Ft670901FF all"), + isc::InvalidParameter); // Some more negative test cases // Base is not specified - EXPECT_THROW(process("perfdhcp -b -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -b -l ethx all"), + isc::InvalidParameter); // Typo: should be mac= instead of mc= - EXPECT_THROW(process("perfdhcp -l ethx -b mc=00:01:02:03::04:05"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, DropTime) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -l ethx -d 12"); + process("perfdhcp -l ethx -d 12 all"); ASSERT_EQ(2, opt.getDropTime().size()); EXPECT_DOUBLE_EQ(12, opt.getDropTime()[0]); EXPECT_DOUBLE_EQ(1, opt.getDropTime()[1]); - process("perfdhcp -l ethx -d 2 -d 4.7"); + process("perfdhcp -l ethx -d 2 -d 4.7 all"); ASSERT_EQ(2, opt.getDropTime().size()); EXPECT_DOUBLE_EQ(2, opt.getDropTime()[0]); EXPECT_DOUBLE_EQ(4.7, opt.getDropTime()[1]); // Negative test cases // Drop time must not be negative - EXPECT_THROW(process("perfdhcp -l ethx -d -2 -d 4.7"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -l ethx -d -9.1 -d 0"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -d -2 -d 4.7 all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -d -9.1 -d 0 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, TimeOffset) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -l ethx -T file1.x -T file2.x -E 4"); + process("perfdhcp -l ethx -T file1.x -T file2.x -E 4 all"); EXPECT_EQ(4, opt.getElapsedTimeOffset()); // Negative test cases // Argument -E must be used with -T - EXPECT_THROW(process("perfdhcp -l ethx -E 3 -i"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -E 3 -i all"), + isc::InvalidParameter); // Value in -E not specified - EXPECT_THROW(process("perfdhcp -l ethx -T file.x -E -i"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -T file.x -E -i all"), + isc::InvalidParameter); // Value for -E must not be negative - EXPECT_THROW(process("perfdhcp -l ethx -E -3 -T file.x"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -E -3 -T file.x all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, ExchangeMode) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -l ethx -i"); + process("perfdhcp -l ethx -i all"); EXPECT_EQ(CommandOptions::DO_SA, opt.getExchangeMode()); // Negative test cases // No template file specified - EXPECT_THROW(process("perfdhcp -i -l ethx -X 3"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -i -l ethx -X 3 all"), + isc::InvalidParameter); // Offsets can't be used in simple exchanges (-i) - EXPECT_THROW(process("perfdhcp -i -l ethx -O 2 -T file.x"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -i -l ethx -E 3 -T file.x"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -i -l ethx -S 1 -T file.x"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -i -l ethx -I 2 -T file.x"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -i -l ethx -O 2 -T file.x all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -i -l ethx -E 3 -T file.x all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -i -l ethx -S 1 -T file.x all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -i -l ethx -I 2 -T file.x all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Offsets) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -E5 -4 -I 2 -S3 -O 30 -X7 -l ethx -X3 -T file1.x -T file2.x"); + process("perfdhcp -E5 -4 -I 2 -S3 -O 30 -X7 -l ethx " + "-X3 -T file1.x -T file2.x all"); EXPECT_EQ(2, opt.getRequestedIpOffset()); EXPECT_EQ(5, opt.getElapsedTimeOffset()); EXPECT_EQ(3, opt.getServerIdOffset()); @@ -304,151 +331,234 @@ TEST_F(CommandOptionsTest, Offsets) { // Negative test cases // IP offset/IA_NA offset must be positive - EXPECT_THROW(process("perfdhcp -6 -I 0 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -6 -I -4 -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -I 0 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -I -4 -l ethx all"), + isc::InvalidParameter); // TODO - other negative cases } TEST_F(CommandOptionsTest, LocalPort) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -l ethx -L 2000"); + process("perfdhcp -l ethx -L 2000 all"); EXPECT_EQ(2000, opt.getLocalPort()); // Negative test cases // Local port must be between 0..65535 - EXPECT_THROW(process("perfdhcp -l ethx -L -2"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -l ethx -L"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -l ethx -L 65540"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -L -2 all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -L all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -L 65540 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Preload) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -1 -P 3 -l ethx"); + process("perfdhcp -1 -P 3 -l ethx all"); EXPECT_EQ(3, opt.getPreload()); // Negative test cases // Number of preload packages must not be negative integer - EXPECT_THROW(process("perfdhcp -P -1 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -P -3 -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -P -1 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -P -3 -l ethx all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Seed) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -6 -P 2 -s 23 -l ethx"); + process("perfdhcp -6 -P 2 -s 23 -l ethx all"); EXPECT_EQ(23, opt.getSeed()); EXPECT_TRUE(opt.isSeeded()); - process("perfdhcp -6 -P 2 -s 0 -l ethx"); + process("perfdhcp -6 -P 2 -s 0 -l ethx all"); EXPECT_EQ(0, opt.getSeed()); EXPECT_FALSE(opt.isSeeded()); // Negtaive test cases // Seed must be non-negative integer - EXPECT_THROW(process("perfdhcp -6 -P 2 -s -5 -l ethx"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -6 -P 2 -s -l ethx"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -P 2 -s -5 -l ethx all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -6 -P 2 -s -l ethx all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, TemplateFiles) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -T file1.x -l ethx"); + process("perfdhcp -T file1.x -l ethx all"); ASSERT_EQ(1, opt.getTemplateFiles().size()); EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]); - process("perfdhcp -T file1.x -s 12 -w start -T file2.x -4 -l ethx"); + process("perfdhcp -T file1.x -s 12 -w start -T file2.x -4 -l ethx all"); ASSERT_EQ(2, opt.getTemplateFiles().size()); EXPECT_EQ("file1.x", opt.getTemplateFiles()[0]); EXPECT_EQ("file2.x", opt.getTemplateFiles()[1]); // Negative test cases // No template file specified - EXPECT_THROW(process("perfdhcp -s 12 -l ethx -T"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -s 12 -T -l ethx all"), + isc::InvalidParameter); // Too many template files specified - EXPECT_THROW(process("perfdhcp -s 12 -l ethx -T file.x -T file.x -T file.x"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -s 12 -l ethx -T file.x " + "-T file.x -T file.x all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Wrapped) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -B -w start -i -l ethx"); + process("perfdhcp -B -w start -i -l ethx all"); EXPECT_EQ("start", opt.getWrapped()); // Negative test cases // Missing command after -w, expected start/stop - EXPECT_THROW(process("perfdhcp -B -i -l ethx -w"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -B -i -l ethx -w all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Diagnostics) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -l ethx -i -x asTe"); + process("perfdhcp -l ethx -i -x asTe all"); EXPECT_EQ("asTe", opt.getDiags()); // Negative test cases // No diagnostics string specified - EXPECT_THROW(process("perfdhcp -l ethx -i -x"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -i -x all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Aggressivity) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -a 10 -l 192.168.0.1"); + process("perfdhcp -a 10 -l 192.168.0.1 all"); EXPECT_EQ(10, opt.getAggressivity()); // Negative test cases // Aggressivity must be non negative integer - EXPECT_THROW(process("perfdhcp -l ethx -a 0"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -l ethx -a"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -a -2 -l ethx -a 3"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -a 0 all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -l ethx -a all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -a -2 -l ethx -a 3 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, MaxDrop) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -D 25 -l ethx -r 10"); + process("perfdhcp -D 25 -l ethx -r 10 all"); EXPECT_EQ(25, opt.getMaxDrop()[0]); - process("perfdhcp -D 25 -l ethx -D 15 -r 10"); + process("perfdhcp -D 25 -l ethx -D 15 -r 10 all"); EXPECT_EQ(25, opt.getMaxDrop()[0]); EXPECT_EQ(15, opt.getMaxDrop()[1]); - process("perfdhcp -D 15% -l ethx -r 10"); + process("perfdhcp -D 15% -l ethx -r 10 all"); EXPECT_EQ(15, opt.getMaxDropPercentage()[0]); - process("perfdhcp -D 15% -D25% -l ethx -r 10"); + process("perfdhcp -D 15% -D25% -l ethx -r 10 all"); EXPECT_EQ(15, opt.getMaxDropPercentage()[0]); EXPECT_EQ(25, opt.getMaxDropPercentage()[1]); - process("perfdhcp -D 1% -D 99% -l ethx -r 10"); + process("perfdhcp -D 1% -D 99% -l ethx -r 10 all"); EXPECT_EQ(1, opt.getMaxDropPercentage()[0]); EXPECT_EQ(99, opt.getMaxDropPercentage()[1]); // Negative test cases // Too many -D options - EXPECT_THROW(process("perfdhcp -D 0% -D 1 -l ethx -r20 -D 3"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -D 0% -D 1 -l ethx -r20 -D 3 all"), + isc::InvalidParameter); // Too many -D options - EXPECT_THROW(process("perfdhcp -D 99% -D 13% -l ethx -r20 -D 10%"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -D 99% -D 13% -l ethx -r20 -D 10% all"), + isc::InvalidParameter); // Percentage is out of bounds - EXPECT_THROW(process("perfdhcp -D101% -D 13% -l ethx -r20"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -D0% -D 13% -l ethx -r20"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -D101% -D 13% -l ethx -r20 all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -D0% -D 13% -l ethx -r20 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, NumRequest) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -n 1000 -r 10 -l ethx"); + process("perfdhcp -n 1000 -r 10 -l ethx all"); EXPECT_EQ(1000, opt.getNumRequests()[0]); - process("perfdhcp -n 5 -r 10 -n 500 -l ethx"); + process("perfdhcp -n 5 -r 10 -n 500 -l ethx all"); EXPECT_EQ(5, opt.getNumRequests()[0]); EXPECT_EQ(500, opt.getNumRequests()[1]); // Negative test cases // Too many -n parameters, expected maximum 2 - EXPECT_THROW(process("perfdhcp -n 1 -n 2 -l ethx -n3 -r 20"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -n 1 -n 2 -l ethx -n3 -r 20 all"), + isc::InvalidParameter); // Num request must be positive integer - EXPECT_THROW(process("perfdhcp -n 1 -n -22 -l ethx -r 10"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -n 0 -l ethx -r 10"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -n 1 -n -22 -l ethx -r 10 all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -n 0 -l ethx -r 10 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, Period) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -p 120 -l ethx -r 100"); + process("perfdhcp -p 120 -l ethx -r 100 all"); EXPECT_EQ(120, opt.getPeriod()); // Negative test cases // Test period must be positive integer - EXPECT_THROW(process("perfdhcp -p 0 -l ethx -r 50"), isc::InvalidParameter); - EXPECT_THROW(process("perfdhcp -p -3 -l ethx -r 50"), isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -p 0 -l ethx -r 50 all"), + isc::InvalidParameter); + EXPECT_THROW(process("perfdhcp -p -3 -l ethx -r 50 all"), + isc::InvalidParameter); +} + +TEST_F(CommandOptionsTest, Interface) { + // In order to make this test portable we need to know + // at least one interface name on OS where test is run. + // Interface Manager has ability to detect interfaces. + dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance(); + const dhcp::IfaceMgr::IfaceCollection& ifaces = iface_mgr.getIfaces(); + std::string iface_name; + CommandOptions& opt = CommandOptions::instance(); + // The local loopback interface should be available. + // If no interface have been found for any reason we should + // not fail this test. + if (ifaces.size() > 0) { + // Get the name of the interface we detected. + iface_name = ifaces.begin()->getName(); + // Use the name in the command parser. + ASSERT_NO_THROW(process("perfdhcp -4 -l " + iface_name + " abc")); + // We expect that command parser will detect that argument + // specified along with '-l' is the interface name. + EXPECT_TRUE(opt.isInterface()); + + // If neither interface nor server is specified then + // exception is expected to be thrown. + EXPECT_THROW(process("perfdhcp -4"), isc::InvalidParameter); + } +} + +TEST_F(CommandOptionsTest, Server) { + CommandOptions& opt = CommandOptions::instance(); + // There is at least server parameter needed. If server is not + // specified the local interface must be specified. + // The server value equal to 'all' means use broadcast. + ASSERT_NO_THROW(process("perfdhcp all")); + // Once command line is parsed we expect that server name is + // set to broadcast address because 'all' was specified. + EXPECT_TRUE(opt.isBroadcast()); + // The broadcast address is 255.255.255.255. + EXPECT_EQ("255.255.255.255", opt.getServerName()); + + // When all is specified for DHCPv6 mode we expect + // FF02::1:2 as a server name which means All DHCP + // servers and relay agents in local network segment + ASSERT_NO_THROW(process("perfdhcp -6 all")); + EXPECT_EQ("FF02::1:2", opt.getServerName()); + + // When server='servers' in DHCPv6 mode we expect + // FF05::1:3 as server name which means All DHCP + // servers in local network. + ASSERT_NO_THROW(process("perfdhcp -6 servers")); + EXPECT_EQ("FF05::1:3", opt.getServerName()); + + // If server name is neither 'all' nor 'servers' + // the given argument value is expected to be + // returned. + ASSERT_NO_THROW(process("perfdhcp -6 abc")); + EXPECT_EQ("abc", opt.getServerName()); } From 8bbc241df84bd1612644de8a8ff7d727a86ae485 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 7 Aug 2012 15:00:14 +0200 Subject: [PATCH 034/148] [1959] Add some more comments to the test_control.cc --- tests/tools/perfdhcp/test_control.cc | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index c050c9f0a6..ffa4d3e5c7 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -130,19 +130,31 @@ TestControl::generateMacAddress() const { if ((clients_num == 0) || (clients_num == 1)) { return options.getMacPrefix(); } + // Get the base MAC address. We are going to randomize part of it. std::vector mac_addr(options.getMacPrefix()); if (mac_addr.size() != HW_ETHER_LEN) { isc_throw(BadValue, "invalid MAC address prefix specified"); } uint32_t r = random(); + // The random number must be in the range 0..clients_num. This + // will guarantee that every client has exactly one random MAC + // address assigned. r %= clients_num; + // Randomize MAC address octets. for (std::vector::iterator it = mac_addr.end() - 1; it >= mac_addr.begin(); --it) { + // Add the random value to the current octet. (*it) += r; if (r < 256) { + // If we are here it means that there is no sense + // to randomize the remaining octets of MAC address + // because the following bytes of random value + // are zero and it will have no effect. break; } + // Randomize the next octet with the following + // byte of random value. r >>= 8; } return mac_addr; @@ -260,6 +272,9 @@ TestControl::receivePackets() { if (!pkt4) { receiving = false; } else { + // TODO: replace this with use of StatsMgr to increase + // number of received packets. This can be done once + // the 1958 ticket is reviewed and checked-in. std::cout << "Received packet" << std::endl; } } @@ -269,9 +284,11 @@ void TestControl::registerOptionFactories4() const { static bool factories_registered = false; if (!factories_registered) { + // DHCP_MESSAGE_TYPE option factory. LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_MESSAGE_TYPE, &TestControl::factoryGeneric4); + // DHCP_PARAMETER_REQUEST_LIST option factory. LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST, &TestControl::factoryRequestList4); @@ -283,6 +300,7 @@ void TestControl::registerOptionFactories6() const { static bool factories_registered = false; if (!factories_registered) { + // This is a placeholder for v6 factories. } factories_registered = true; } @@ -340,12 +358,15 @@ void TestControl::sendDiscover4(const TestControlSocket& socket) { ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); + // Generate the MAC address to be passed in the packet. std::vector mac_address = generateMacAddress(); + // Generate trasnaction id to be set for the new exchange. const uint32_t transid = static_cast(random()); boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); if (!pkt4) { isc_throw(Unexpected, "failed to create DISCOVER packet"); } + // Set options: DHCP_MESSAGE_TYPE and DHCP_PARAMETER_REQUEST_LIST OptionBuffer buf_msg_type; buf_msg_type.push_back(DHCPDISCOVER); pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, @@ -353,6 +374,8 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST)); + // Set client's and server's ports as well as server's address, + // and local (relay) address. setDefaults4(socket, pkt4); pkt4->pack(); IfaceMgr::instance().send(pkt4); @@ -362,11 +385,17 @@ void TestControl::setDefaults4(const TestControlSocket &socket, const boost::shared_ptr& pkt) { CommandOptions& options = CommandOptions::instance(); + // Interface name. pkt->setIface(socket.getIface()); + // Local client's port (68) pkt->setLocalPort(DHCP4_CLIENT_PORT); + // Server's port (67) pkt->setRemotePort(DHCP4_SERVER_PORT); + // The remote server's name or IP. pkt->setRemoteAddr(IOAddress(options.getServerName())); + // Set relay (GIADDR) address to local address. pkt->setGiaddr(IOAddress(socket.getAddress())); + // Pretend that we have one relay (which is us). pkt->setHops(1); } From 25ae3625bc6da890c449bdca3d6b6f27a1fff0a2 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 7 Aug 2012 20:10:47 +0200 Subject: [PATCH 035/148] [1959] Enabled Solicit packets creation and send. --- tests/tools/perfdhcp/test_control.cc | 125 +++++++++++++++++++++++++-- tests/tools/perfdhcp/test_control.h | 36 +++++++- 2 files changed, 150 insertions(+), 11 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index ffa4d3e5c7..c956da425e 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -96,13 +96,50 @@ TestControl::checkExitConditions() const { } OptionPtr -TestControl::factoryGeneric4(Option::Universe u, - uint16_t type, - const OptionBuffer& buf) { +TestControl::factoryElapsedTimeSolicit6(Option::Universe, uint16_t, + const OptionBuffer&) { + return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(2, 0))); +} + +OptionPtr +TestControl::factoryGeneric(Option::Universe u, uint16_t type, + const OptionBuffer& buf) { OptionPtr opt(new Option(u, type, buf)); return opt; } +OptionPtr +TestControl::factoryIana6(Option::Universe, uint16_t, + const OptionBuffer&) { + const uint8_t buf_array[] = { + 0, 0, 0, 1, // IAID = 1 + 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600 + 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400 + }; + OptionBuffer buf(buf_array, buf_array + sizeof(buf_array)); + return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf)); +} + +OptionPtr +TestControl::factoryRapidCommit6(Option::Universe, uint16_t, + const OptionBuffer&) { + return OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())); +} + +OptionPtr +TestControl::factoryOptionRequestOption6(Option::Universe, + uint16_t, + const OptionBuffer&) { + const uint8_t buf_array[] = { + D6O_NAME_SERVERS, + D6O_DOMAIN_SEARCH + }; + OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); + return OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)); +} + + OptionPtr TestControl::factoryRequestList4(Option::Universe u, uint16_t type, @@ -123,6 +160,8 @@ TestControl::factoryRequestList4(Option::Universe u, return opt; } + + std::vector TestControl::generateMacAddress() const { CommandOptions& options = CommandOptions::instance(); @@ -160,6 +199,18 @@ TestControl::generateMacAddress() const { return mac_addr; } +std::vector +TestControl::generateDuid() const { + CommandOptions& options = CommandOptions::instance(); + uint32_t clients_num = options.getClientsNum(); + if ((clients_num == 0) || (clients_num == 1)) { + return options.getDuidPrefix(); + } + // Get the base MAC address. We are going to randomize part of it. + std::vector duid(options.getDuidPrefix()); + return duid; +} + uint64_t TestControl::getNextExchangesNum() const { CommandOptions& options = CommandOptions::instance(); @@ -287,7 +338,7 @@ TestControl::registerOptionFactories4() const { // DHCP_MESSAGE_TYPE option factory. LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_MESSAGE_TYPE, - &TestControl::factoryGeneric4); + &TestControl::factoryGeneric); // DHCP_PARAMETER_REQUEST_LIST option factory. LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST, @@ -300,7 +351,24 @@ void TestControl::registerOptionFactories6() const { static bool factories_registered = false; if (!factories_registered) { - // This is a placeholder for v6 factories. + LibDHCP::OptionFactoryRegister(Option::V6, + D6O_ELAPSED_TIME, + &TestControl::factoryElapsedTimeSolicit6); + LibDHCP::OptionFactoryRegister(Option::V6, + D6O_RAPID_COMMIT, + &TestControl::factoryRapidCommit6); + LibDHCP::OptionFactoryRegister(Option::V6, + D6O_ORO, + &TestControl::factoryOptionRequestOption6); + LibDHCP::OptionFactoryRegister(Option::V6, + D6O_CLIENTID, + &TestControl::factoryGeneric); + + LibDHCP::OptionFactoryRegister(Option::V6, + D6O_IA_NA, + &TestControl::factoryIana6); + + } factories_registered = true; } @@ -347,7 +415,11 @@ TestControl::run() { receivePackets(); for (uint64_t i = packets_due; i > 0; --i) { - sendDiscover4(socket); + if (options.getIpVersion() == 4) { + sendDiscover4(socket); + } else { + sendSolicit6(socket); + } ++packets_sent; cout << "Packets sent " << packets_sent << endl; } @@ -382,7 +454,32 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { } void -TestControl::setDefaults4(const TestControlSocket &socket, +TestControl::sendSolicit6(const TestControlSocket& socket) { + ++sent_packets_0_; + last_sent_ = microsec_clock::universal_time(); + // Generate the MAC address to be passed in the packet. + std::vector mac_address = generateMacAddress(); + // Generate DUID to be passed to the packet + std::vector duid = generateDuid(); + // Generate trasnaction id to be set for the new exchange. + const uint32_t transid = static_cast(random()); + boost::shared_ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + if (!pkt6) { + isc_throw(Unexpected, "failed to create SOLICIT packet"); + } + pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME)); + pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT)); + pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid)); + pkt6->addOption(Option::factory(Option::V6, D6O_ORO)); + pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA)); + + setDefaults6(socket, pkt6); + pkt6->pack(); + IfaceMgr::instance().send(pkt6); +} + +void +TestControl::setDefaults4(const TestControlSocket& socket, const boost::shared_ptr& pkt) { CommandOptions& options = CommandOptions::instance(); // Interface name. @@ -399,6 +496,20 @@ TestControl::setDefaults4(const TestControlSocket &socket, pkt->setHops(1); } +void +TestControl::setDefaults6(const TestControlSocket& socket, + const boost::shared_ptr& pkt) { + CommandOptions& options = CommandOptions::instance(); + // Interface name. + pkt->setIface(socket.getIface()); + // Local client's port (547) + pkt->setLocalPort(DHCP6_CLIENT_PORT); + // Server's port (548) + pkt->setRemotePort(DHCP6_SERVER_PORT); + // The remote server's name or IP. + pkt->setRemoteAddr(IOAddress(options.getServerName())); +} + void TestControl::updateSendDue() { // If default constructor was called, this should not happen but diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index bb1f283712..07a6496c9c 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -132,6 +133,12 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; + static dhcp::OptionPtr + factoryElapsedTimeSolicit6(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + + /// \brief Factory function to create generic option. /// /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister. @@ -147,9 +154,23 @@ private: /// \param type option-type. /// \param buf option-buffer. /// \return instance o the generic option. - static dhcp::OptionPtr factoryGeneric4(dhcp::Option::Universe u, - uint16_t type, - const dhcp::OptionBuffer& buf); + static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + + static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + + static dhcp::OptionPtr + factoryOptionRequestOption6(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + + static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + /// \brief Factory function to create DHCPv4 Request List option. /// @@ -177,6 +198,8 @@ private: uint16_t type, const dhcp::OptionBuffer& buf); + std::vector generateDuid() const; + /// \brief Generate MAC address. /// /// This method generates MAC address. The number of unique @@ -256,7 +279,9 @@ private: /// \param socket socket to be used to send the message. /// \throw isc::Unexpected if failed to create new packet instance. /// \throw isc::BadValue if MAC address has invalid length. - void sendDiscover4(const TestControlSocket &socket); + void sendDiscover4(const TestControlSocket& socket); + + void sendSolicit6(const TestControlSocket& socket); /// \brief Set default DHCPv4 packet data. /// @@ -273,6 +298,9 @@ private: void setDefaults4(const TestControlSocket& socket, const boost::shared_ptr& pkt); + void setDefaults6(const TestControlSocket& socket, + const boost::shared_ptr& pkt); + /// \brief Update due time to initiate next chunk of exchanges. /// /// Method updates due time to initiate next chunk of exchanges. From 967e3ec6188b8a41e7f830bd13deda30afe5fa44 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 8 Aug 2012 20:03:13 +0200 Subject: [PATCH 036/148] [1959] Added generation of DUID prefix if it is not given by user. --- tests/tools/perfdhcp/command_options.cc | 38 +++++++++++++++++++ tests/tools/perfdhcp/command_options.h | 6 +++ .../tests/command_options_unittest.cc | 16 +++++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index 55380d086b..210ed04920 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -20,8 +20,10 @@ #include #include #include +#include #include +#include #include #include "command_options.h" @@ -367,6 +369,12 @@ CommandOptions::initialize(int argc, char** argv) { isc_throw(InvalidParameter, "without an inteface server is required"); } + + // If DUID is not specified from command line we need to + // generate one. + if (duid_prefix_.size() == 0) { + generateDuidPrefix(); + } } void @@ -476,6 +484,36 @@ CommandOptions::decodeDuid(const std::string& base) { } } +void +CommandOptions::generateDuidPrefix() { + using namespace boost::posix_time; + // Duid prefix will be most likely generated only once but + // it is ok if it is called more then once so we simply + // regenerate it and discard previous value. + duid_prefix_.clear(); + const uint8_t duid_prefix_len = 14; + duid_prefix_.resize(duid_prefix_len); + // The first four octets consist of DUID LLT and hardware type. + duid_prefix_[0] = DUID_LLT >> 8; + duid_prefix_[1] = DUID_LLT & 0xff; + duid_prefix_[2] = HWTYPE_ETHERNET >> 8; + duid_prefix_[3] = HWTYPE_ETHERNET & 0xff; + + // As described in RFC3315: 'the time value is the time + // that the DUID is generated represented in seconds + // since midnight (UTC), January 1, 2000, modulo 2^32.' + ptime now = microsec_clock::universal_time(); + ptime duid_epoch(from_iso_string("20000101T000000")); + time_period period(duid_epoch, now); + uint32_t duration_sec = htonl(period.length().total_seconds()); + memcpy(&duid_prefix_[4], &duration_sec, 4); + + // Set link layer address (6 octets). This value may be + // randomized before sending a packet to simulate different + // clients. + memcpy(&duid_prefix_[8], &mac_prefix_[0], 6); +} + uint8_t CommandOptions::convertHexString(const std::string& text) const { unsigned int ui = 0; diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h index 459efa598b..b75c43864c 100644 --- a/tests/tools/perfdhcp/command_options.h +++ b/tests/tools/perfdhcp/command_options.h @@ -346,6 +346,12 @@ private: /// \param base Base string given as -b duid=0F1234 /// \throws isc::InvalidParameter if DUID is invalid void decodeDuid(const std::string& base); + + /// \brief Generates DUID-LLT (based on link layer address). + /// + /// Function generates DUID based on link layer address and + /// initiates duid_prefix_ value with it. + void generateDuidPrefix(); /// \brief Converts two-digit hexadecimal string to a byte /// diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index 669d792bb5..e3e3384b22 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -71,11 +71,25 @@ protected: EXPECT_EQ(0, opt.getClientsNum()); // default mac - uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 }; + const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 }; std::vector v1 = opt.getMacPrefix(); ASSERT_EQ(6, v1.size()); EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + // Check if DUID is initialized. The DUID-LLT is expected + // to start with DUID_LLT value of 1 and hardware ethernet + // type equal to 1 (HWETHER_TYPE). + const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 }; + // We assume DUID-LLT length 14. This includes 4 octets of + // DUID_LLT value, two octets of hardware type, 4 octets + // of time value and 6 octets of variable link layer (MAC) + // address. + const int duid_llt_size = 14; + std::vector v2 = opt.getDuidPrefix(); + ASSERT_EQ(duid_llt_size, opt.getDuidPrefix().size()); + EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4, + duid_llt_and_hw)); + EXPECT_EQ(0, opt.getBase().size()); EXPECT_EQ(0, opt.getNumRequests().size()); EXPECT_EQ(0, opt.getPeriod()); From ce6188b38f1b684459bc645a13b951453c526108 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 8 Aug 2012 20:04:20 +0200 Subject: [PATCH 037/148] [1959] Added multicast option on the socket if remote addr is multicast. --- tests/tools/perfdhcp/test_control.cc | 60 +++++++++++++++++++++++----- tests/tools/perfdhcp/test_control.h | 13 +++++- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index c956da425e..ed9018e794 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -62,6 +62,7 @@ TestControl::TestControlSocket::initSocketData() { ++s) { if (s->sockfd_ == socket_) { iface_ = it->getName(); + ifindex_ = it->getIndex(); addr_ = s->addr_; return; } @@ -267,6 +268,7 @@ TestControl::openSocket() const { uint8_t family = AF_INET; uint16_t port = 67; int sock = 0; + IOAddress remoteaddr(servername); if (options.getIpVersion() == 6) { family = AF_INET6; port = 547; @@ -289,7 +291,6 @@ TestControl::openSocket() const { } else if (!servername.empty()) { // If only server name is given we will need to try to resolve // the local address to bind socket to based on remote address. - IOAddress remoteaddr(servername); sock = IfaceMgr::instance().openSocketFromRemoteAddress(remoteaddr, port); } @@ -309,8 +310,34 @@ TestControl::openSocket() const { isc_throw(InvalidOperation, "unable to set broadcast option on the socket"); } + } else if (options.getIpVersion() == 6) { + // If remote address is multicast we need to enable it on + // the socket that has been created. + asio::ip::address_v6 remote_v6 = remoteaddr.getAddress().to_v6(); + if (remote_v6.is_multicast()) { + int hops = 1; + int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hops, sizeof(hops)); + // If user specified interface name with '-l' the + // IPV6_MULTICAST_IF has to be set. + if ((ret >= 0) && options.isInterface()) { + IfaceMgr::Iface* iface = + IfaceMgr::instance().getIface(options.getLocalName()); + if (iface == NULL) { + isc_throw(Unexpected, "unknown interface " + << options.getLocalName()); + } + int idx = iface->getIndex(); + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &idx, sizeof(idx)); + } + if (ret < 0) { + isc_throw(InvalidOperation, + "unable to enable multicast on socket " << sock + << ". errno = " << errno); + } + } } - return(sock); } @@ -319,14 +346,23 @@ TestControl::receivePackets() { int timeout = 0; bool receiving = true; while (receiving) { - Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout); - if (!pkt4) { - receiving = false; - } else { - // TODO: replace this with use of StatsMgr to increase - // number of received packets. This can be done once - // the 1958 ticket is reviewed and checked-in. - std::cout << "Received packet" << std::endl; + if (CommandOptions::instance().getIpVersion() == 4) { + Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout); + if (!pkt4) { + receiving = false; + } else { + // TODO: replace this with use of StatsMgr to increase + // number of received packets. This can be done once + // the 1958 ticket is reviewed and checked-in. + std::cout << "Received packet" << std::endl; + } + } else if (CommandOptions::instance().getIpVersion() == 6) { + Pkt6Ptr pkt6 = IfaceMgr::instance().receive6(); + if (!pkt6) { + receiving = false; + } else { + std::cout << "Received DHCPv6 packet" << std::endl; + } } } } @@ -484,6 +520,8 @@ TestControl::setDefaults4(const TestControlSocket& socket, CommandOptions& options = CommandOptions::instance(); // Interface name. pkt->setIface(socket.getIface()); + // Interface index. + pkt->setIndex(socket.getIfIndex()); // Local client's port (68) pkt->setLocalPort(DHCP4_CLIENT_PORT); // Server's port (67) @@ -502,6 +540,8 @@ TestControl::setDefaults6(const TestControlSocket& socket, CommandOptions& options = CommandOptions::instance(); // Interface name. pkt->setIface(socket.getIface()); + // Interface index. + pkt->setIndex(socket.getIfIndex()); // Local client's port (547) pkt->setLocalPort(DHCP6_CLIENT_PORT); // Server's port (548) diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 07a6496c9c..9670cb72a1 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -68,6 +68,11 @@ public: /// \return name of the interface where socket is bound to. const std::string& getIface() const { return(iface_); } + /// \brief Return interface index where socket is bound to. + /// + /// \return index fo the interface where sockert is bound to. + int getIfIndex() const { return(ifindex_); } + /// \brief Return address where socket is bound to. /// /// \return address where socket is bound to. @@ -91,6 +96,7 @@ public: int socket_; ///< Socket descirptor. std::string iface_; ///< Name of the interface. + int ifindex_; ///< Index of the interface. asiolink::IOAddress addr_; ///< Address bound. }; @@ -231,11 +237,16 @@ private: /// to create a socket, depending on what is available (specified /// from the command line). If socket can't be created for any /// reason, exception is thrown. + /// If destination address is broadcast (for DHCPv4) or multicast + /// (for DHCPv6) than broadcast or multicast option is set on + /// the socket. /// /// \throw isc::BadValue if socket can't be created for given /// interface, local address or remote address. /// \throw isc::InvalidOperation if broadcast option can't be - /// set for the socket. + /// set for the v4 socket or if multicast option cat't be set + /// for the v6 socket. + /// \throw isc::Unexpected if interal unexpected error occured. /// \return socket descriptor. int openSocket() const; From 8e7ce81608718bc14740240158ae60de162734de Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 14 Aug 2012 13:36:57 +0200 Subject: [PATCH 038/148] [1959] Extended unit testing of TestControl class. --- tests/tools/perfdhcp/command_options.cc | 12 +- tests/tools/perfdhcp/test_control.cc | 55 +- tests/tools/perfdhcp/test_control.h | 146 ++++- .../perfdhcp/tests/command_options_helper.h | 106 ++++ .../tests/command_options_unittest.cc | 11 +- .../perfdhcp/tests/test_control_unittest.cc | 576 +++++++++++++++++- 6 files changed, 825 insertions(+), 81 deletions(-) create mode 100644 tests/tools/perfdhcp/tests/command_options_helper.h diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index 210ed04920..14a2e65b9a 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -57,8 +57,9 @@ CommandOptions::reset() { report_delay_ = 0; clients_num_ = 0; mac_prefix_.assign(mac, mac + 6); - base_.resize(0); - num_request_.resize(0); + duid_prefix_.clear(); + base_.clear(); + num_request_.clear(); period_ = 0; drop_time_set_ = 0; drop_time_.assign(dt, dt + 2); @@ -83,6 +84,8 @@ CommandOptions::reset() { diags_.clear(); wrapped_.clear(); server_name_.clear(); + + generateDuidPrefix(); } void @@ -461,6 +464,7 @@ CommandOptions::decodeMac(const std::string& base) { void CommandOptions::decodeDuid(const std::string& base) { // Strip argument from duid= + std::vector duid_prefix; size_t found = base.find('='); check(found == std::string::npos, "expected -b format for duid is -b duid="); std::string b = base.substr(found + 1); @@ -480,8 +484,10 @@ CommandOptions::decodeDuid(const std::string& base) { isc_throw(isc::InvalidParameter, "invalid characters in DUID provided, exepected hex digits"); } - duid_prefix_.push_back(static_cast(ui)); + duid_prefix.push_back(static_cast(ui)); } + // Assign the new duid only if successfully generated. + std::swap(duid_prefix, duid_prefix_); } void diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index ed9018e794..ebc3f40f9b 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -97,10 +97,16 @@ TestControl::checkExitConditions() const { } OptionPtr -TestControl::factoryElapsedTimeSolicit6(Option::Universe, uint16_t, - const OptionBuffer&) { - return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, - OptionBuffer(2, 0))); +TestControl::factoryElapsedTime6(Option::Universe, uint16_t, + const OptionBuffer& buf) { + if (buf.size() == 2) { + return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf)); + } else if (buf.size() == 0) { + return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(2, 0))); + } + isc_throw(isc::BadValue, + "elapsed time option buffer size has to be 0 or 2"); } OptionPtr @@ -112,14 +118,17 @@ TestControl::factoryGeneric(Option::Universe u, uint16_t type, OptionPtr TestControl::factoryIana6(Option::Universe, uint16_t, - const OptionBuffer&) { + const OptionBuffer& buf) { const uint8_t buf_array[] = { 0, 0, 0, 1, // IAID = 1 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400 }; - OptionBuffer buf(buf_array, buf_array + sizeof(buf_array)); - return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf)); + OptionBuffer buf_ia_na(buf_array, buf_array + sizeof(buf_array)); + for (int i = 0; i < buf.size(); ++i) { + buf_ia_na.push_back(buf[i]); + } + return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)); } OptionPtr @@ -207,8 +216,13 @@ TestControl::generateDuid() const { if ((clients_num == 0) || (clients_num == 1)) { return options.getDuidPrefix(); } - // Get the base MAC address. We are going to randomize part of it. + // Get the base DUID. We are going to randomize part of it. std::vector duid(options.getDuidPrefix()); + std::vector mac_addr(generateMacAddress()); + duid.resize(duid.size() - mac_addr.size()); + for (int i = 0; i < mac_addr.size(); ++i) { + duid.push_back(mac_addr[i]); + } return duid; } @@ -227,12 +241,6 @@ TestControl::getNextExchangesNum() const { // synchornize with it. if (options.getRate() != 0) { time_period period(send_due_, now); - // Null condition should not occur because we - // have checked it in the first if statement but - // let's keep this check just in case. - if (period.is_null()) { - return (0); - } time_duration duration = period.length(); // due_factor indicates the number of seconds that // sending next chunk of packets will take. @@ -261,17 +269,22 @@ TestControl::getNextExchangesNum() const { } int -TestControl::openSocket() const { +TestControl::openSocket(uint16_t port) const { CommandOptions& options = CommandOptions::instance(); std::string localname = options.getLocalName(); std::string servername = options.getServerName(); uint8_t family = AF_INET; - uint16_t port = 67; int sock = 0; IOAddress remoteaddr(servername); + if (port == 0) { + if (options.getIpVersion() == 6) { + port = 547; + } else if (port == 0) { + port = 67; + } + } if (options.getIpVersion() == 6) { family = AF_INET6; - port = 547; } // Local name is specified along with '-l' option. // It may point to interface name or local address. @@ -332,7 +345,7 @@ TestControl::openSocket() const { &idx, sizeof(idx)); } if (ret < 0) { - isc_throw(InvalidOperation, + isc_throw(InvalidOperation, "unable to enable multicast on socket " << sock << ". errno = " << errno); } @@ -389,7 +402,7 @@ TestControl::registerOptionFactories6() const { if (!factories_registered) { LibDHCP::OptionFactoryRegister(Option::V6, D6O_ELAPSED_TIME, - &TestControl::factoryElapsedTimeSolicit6); + &TestControl::factoryElapsedTime6); LibDHCP::OptionFactoryRegister(Option::V6, D6O_RAPID_COMMIT, &TestControl::factoryRapidCommit6); @@ -528,6 +541,8 @@ TestControl::setDefaults4(const TestControlSocket& socket, pkt->setRemotePort(DHCP4_SERVER_PORT); // The remote server's name or IP. pkt->setRemoteAddr(IOAddress(options.getServerName())); + // Set local addresss. + pkt->setLocalAddr(IOAddress(socket.getAddress())); // Set relay (GIADDR) address to local address. pkt->setGiaddr(IOAddress(socket.getAddress())); // Pretend that we have one relay (which is us). @@ -546,6 +561,8 @@ TestControl::setDefaults6(const TestControlSocket& socket, pkt->setLocalPort(DHCP6_CLIENT_PORT); // Server's port (548) pkt->setRemotePort(DHCP6_SERVER_PORT); + // Set local address. + pkt->setLocalAddr(socket.getAddress()); // The remote server's name or IP. pkt->setRemoteAddr(IOAddress(options.getServerName())); } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 9670cb72a1..de3b942ade 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -33,6 +33,14 @@ namespace perfdhcp { /// This class is responsible for executing DHCP performance /// test end to end. /// +/// Option factory functions are registered using +/// \ref LibDHCP::OptionFactoryRegister. Registered factory functions +/// provide a way to create options of the same type in the same way. +/// When new option instance is needed the corresponding factory +/// function is called to create it. This is done by calling +/// \ref Option::factory with DHCP message type specified as one of +/// parameters. Some of the parameters passed to factory function +/// may be ignored (e.g. option buffer). class TestControl : public boost::noncopyable { public: @@ -119,11 +127,16 @@ public: /// \throw isc::Unexpected if internal Test Controler error occured. void run(); -private: +protected: - /// \brief Private default constructor. + // We would really like these methods and members to be private but + // they have to be accessible for unit-testing. Another, possibly better, + // solution is to make this class friend of test class but this is not + // what's followed in other classes. + + /// \brief Default constructor. /// - /// Default constructor is private as the object can be created + /// Default constructor is protected as the object can be created /// only via \ref instance method. TestControl(); @@ -139,40 +152,76 @@ private: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; - static dhcp::OptionPtr - factoryElapsedTimeSolicit6(dhcp::Option::Universe u, - uint16_t type, - const dhcp::OptionBuffer& buf); - - /// \brief Factory function to create generic option. + /// \brief Factory function to create DHCPv6 ELAPSED_TIME option. /// - /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister. - /// Registered factory functions provide a way to create options of the - /// same type in the same way. When new option instance is needed the - /// corresponding factory function is called to create it. This is done - /// by calling \ref Option::factory with DHCP message type specified as - /// one of parameters. Some of the parameters passed to factory function - /// may be ignored (e.g. option buffer). For generic option however, factory - /// function creates option using contents of the buffer. + /// This factory function creates DHCPv6 ELAPSED_TIME option instance. + /// If empty buffer is passed the option buffer will be initialized + /// to length 2 and values will be initialized to zeros. Otherwise + /// function will initialize option buffer with values in passed buffer. /// /// \param u universe (V6 or V4). /// \param type option-type. /// \param buf option-buffer. - /// \return instance o the generic option. + /// \throw if elapsed time buffer size is neither 2 nor 0. + /// \return instance o the option. + static dhcp::OptionPtr + factoryElapsedTime6(dhcp::Option::Universe u, + uint16_t type, + const dhcp::OptionBuffer& buf); + + /// \brief Factory function to create generic option. + /// + /// This factory function creates option with specified universe, + /// type and buf. It does not have any additional logic validating + /// the buffer contents, size etc. + /// + /// \param u universe (V6 or V4). + /// \param type option-type. + /// \param buf option-buffer. + /// \return instance o the option. static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); + /// \brief Factory function to create IA_NA option. + /// + /// This factory function creates DHCPv6 IA_NA option instance. + /// \TODO: add support for IA Address options. + /// \param u universe (V6 or V4). + /// \param type option-type. + /// \param buf option-buffer. + /// \return instance of IA_NA option. static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); + /// \brief Factory function to create DHCPv6 ORO option. + /// + /// This factory function creates DHCPv6 Option Request Option instance. + /// The created option will contain the following set of requested options: + /// - D6O_NAME_SERVERS + /// - D6O_DOMAIN_SEARCH + /// + /// \param u universe (V6 or V4). + /// \param type option-type. + /// \param buf option-buffer (ignored and should be empty). + /// \return instance of ORO option. static dhcp::OptionPtr factoryOptionRequestOption6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); + /// \brief Factory function to create DHCPv6 RAPID_COMMIT option instance. + /// + /// This factory function creates DHCPv6 RAPID_COMMIT option instance. + /// The buffer passed to this option must be empty because option does + /// not have any payload. + /// + /// \param u universe (V6 or V4). + /// \param type option-type. + /// \param buf option-buffer (ignored and should be empty). + /// \return instance of RAPID_COMMIT option.. static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); @@ -180,14 +229,8 @@ private: /// \brief Factory function to create DHCPv4 Request List option. /// - /// Factory function is registered using \ref LibDHCP::OptionFactoryRegister. - /// Registered factory functions provide a way to create options of the - /// same type in the same way. When new option instance is needed the - /// corresponding factory function is called to create it. This is done - /// by calling \ref Option::factory with DHCP message type specified as - /// one of parameters. This factory function ignores contents of the - /// buffer provided and creates option buffer internally with the following - /// list of requested options: + /// This factory function creayes DHCPv4 PARAMETER_REQUEST_LIST option + /// instance with the following set of requested options: /// - DHO_SUBNET_MASK, /// - DHO_BROADCAST_ADDRESS, /// - DHO_TIME_OFFSET, @@ -198,12 +241,23 @@ private: /// /// \param u universe (V6 or V4). /// \param type option-type. - /// \param buf option-buffer. + /// \param buf option-buffer (ignored and should be empty). /// \return instance o the generic option. static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& buf); + /// \brief Generate DUID. + /// + /// Method generates unique DUID. The number of DUIDs it can generate + /// depends on the number of simulated clinets, which is specified + /// from the command line. It uses \ref CommandOptions object to retrieve + /// number of clinets. Since the last six octets of DUID are constructed + /// from the MAC address, this function uses \ref generateMacAddress + /// internally to randomize the DUID. + /// + /// \throw isc::BadValue if \ref generateMacAddress throws. + /// \return vector representing DUID. std::vector generateDuid() const; /// \brief Generate MAC address. @@ -241,6 +295,7 @@ private: /// (for DHCPv6) than broadcast or multicast option is set on /// the socket. /// + /// \param port port to bound socket to. /// \throw isc::BadValue if socket can't be created for given /// interface, local address or remote address. /// \throw isc::InvalidOperation if broadcast option can't be @@ -248,8 +303,11 @@ private: /// for the v6 socket. /// \throw isc::Unexpected if interal unexpected error occured. /// \return socket descriptor. - int openSocket() const; + int openSocket(uint16_t port = 0) const; + /// \brief Receive DHCPv4 or DHCPv6 packets from the server. + /// + /// Method receives DHCPv4 or DHCPv6 packets from the server. void receivePackets(); /// \brief Register option factory functions for DHCPv4 @@ -292,11 +350,23 @@ private: /// \throw isc::BadValue if MAC address has invalid length. void sendDiscover4(const TestControlSocket& socket); + /// \brief Send DHCPv6 SOLICIT message. + /// + /// Method creates and sends DHCPv6 SOLICIT message to the server + /// with the following options: + /// - D6O_ELAPSED_TIME, + /// - D6O_RAPID_COMMIT if rapid commit is requested in command line, + /// - D6O_CLIENTID, + /// - D6O_ORO (Option Request Option), + /// - D6O_IA_NA. + /// + /// \param socket socket to be used to send the message. + /// \throw isc::Unexpected if failed to create new packet instance. void sendSolicit6(const TestControlSocket& socket); - /// \brief Set default DHCPv4 packet data. + /// \brief Set default DHCPv4 packet parameters. /// - /// This method sets default data on the DHCPv4 packet: + /// This method sets default parameters on the DHCPv4 packet: /// - interface name, /// - local port = 68 (DHCP client port), /// - remote port = 67 (DHCP server port), @@ -305,10 +375,22 @@ private: /// - hops = 1 (pretending that we are a relay) /// /// \param socket socket used to send the packet. - /// \param pkt packet to be configured. + /// \param pkt reference to packet to be configured. void setDefaults4(const TestControlSocket& socket, const boost::shared_ptr& pkt); + /// \brief Set default DHCPv6 packet parameters. + /// + /// This method sets default parameters on the DHCPv6 packet: + /// - interface name, + /// - interface index, + /// - local port, + /// - remote port, + /// - local address, + /// - remote address (server). + /// + /// \param socket socket used to send the packet. + /// \param pkt reference to packet to be configured. void setDefaults6(const TestControlSocket& socket, const boost::shared_ptr& pkt); @@ -319,6 +401,8 @@ private: /// expected rate in its calculations. void updateSendDue(); +private: + boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk ///< of exchanges. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange diff --git a/tests/tools/perfdhcp/tests/command_options_helper.h b/tests/tools/perfdhcp/tests/command_options_helper.h new file mode 100644 index 0000000000..5886c1fad7 --- /dev/null +++ b/tests/tools/perfdhcp/tests/command_options_helper.h @@ -0,0 +1,106 @@ +// 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 __COMMAND_OPTIONS_HELPER_H +#define __COMMAND_OPTIONS_HELPER_H + +#include +#include + +#include +#include "../command_options.h" + +namespace isc { +namespace perfdhcp { + +/// \brief Command Options Helper class. +/// +/// This helper class can be shared between unit tests that +/// need to initialize CommandOptions objects and feed it with +/// specific command line. The command line can be given as a +/// string represinting program name, options and arguments. +/// The static method exposed by this class can be used to +/// tokenize this string into array of C-strings that are later +/// consumed by \ref CommandOptions::parse. The state of the +/// CommandOptions object is reset every time the process +/// function is invoked. Also, when command line parsing is +/// ended the array of C-string is freed from the memory. +class CommandOptionsHelper { +public: + + class ArgvPtr { + public: + ArgvPtr(char** argv, int argc) : argv_(argv), argc_(argc) { } + char** getArgv() const { return(argv_); } + int getArgc() const { return(argc_); } + + ~ArgvPtr() { + if (argv_ != NULL) { + for(int i = 0; i < argc_; ++i) { + free(argv_[i]); + argv_[i] = NULL; + } + free(argv_); + } + } + + public: + char** argv_; + int argc_; + }; + + static void process(const std::string& cmdline) { + CommandOptions& opt = CommandOptions::instance(); + int argc = 0; + char** argv = tokenizeString(cmdline, argc); + ArgvPtr args(argv, argc); + opt.reset(); + opt.parse(args.getArgc(), args.getArgv()); + } + +private: + + static char** tokenizeString(const std::string& text_to_split, int& num) { + char** results = NULL; + // Tokenization with std streams + std::stringstream text_stream(text_to_split); + // Iterators to be used for tokenization + std::istream_iterator text_iterator(text_stream); + std::istream_iterator text_end; + // Tokenize string (space is a separator) using begin and end iteratos + std::vector tokens(text_iterator, text_end); + + if (tokens.size() > 0) { + // Allocate array of C-strings where we will store tokens + results = static_cast(malloc(tokens.size() * sizeof(char*))); + if (results == NULL) { + isc_throw(Unexpected, "unable to allocate array of c-strings"); + } + // Store tokens in C-strings array + for (int i = 0; i < tokens.size(); ++i) { + char* cs = static_cast(malloc(tokens[i].length() + 1)); + strcpy(cs, tokens[i].c_str()); + results[i] = cs; + } + // Return number of tokens to calling function + num = tokens.size(); + } + return results; + } +}; + +} // namespace perfdhcp +} // namespace isc + +#endif // __COMMAND_OPTIONS_HELPER_H diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index e3e3384b22..faed8a1e6f 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -245,7 +245,8 @@ TEST_F(CommandOptionsTest, Base) { process("perfdhcp -6 -b MAC=10::20::30::40::50::60 " "-l ethx -b duiD=1AB7F5670901FF all"); uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 }; - uint8_t duid[7] = { 0x1A, 0xB7, 0xF5, 0x67, 0x09, 0x01, 0xFF }; + uint8_t duid[14] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 }; // Test Mac std::vector v1 = opt.getMacPrefix(); @@ -256,11 +257,15 @@ TEST_F(CommandOptionsTest, Base) { isc::InvalidParameter); // Test DUID + EXPECT_NO_THROW( + process("perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all") + ); std::vector v2 = opt.getDuidPrefix(); ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size()); EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); - // "t" is invalid digit in DUID - EXPECT_THROW(process("perfdhcp -6 -l ethx -b duiD=1AB7Ft670901FF all"), + // "t" is invalid character in DUID + EXPECT_THROW(process("perfdhcp -6 -l ethx -b " + "duiD=010101010101010101t110111F14 all"), isc::InvalidParameter); // Some more negative test cases diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 2cc6b93f53..aa8983051e 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -17,14 +17,50 @@ #include #include +#include + +#include +#include +#include +#include +#include "command_options_helper.h" #include "../test_control.h" -#include "../command_options.h" -#include "exceptions/exceptions.h" using namespace std; +using namespace boost::posix_time; using namespace isc; +using namespace isc::dhcp; using namespace isc::perfdhcp; +/// \brief Test Control class with protected members made public. +/// +/// This class makes protected TestControl class'es member public +/// to allow unit testing. +class NakedTestControl: public TestControl { +public: + using TestControl::checkExitConditions; + using TestControl::factoryElapsedTime6; + using TestControl::factoryGeneric; + using TestControl::factoryIana6; + using TestControl::factoryOptionRequestOption6; + using TestControl::factoryRapidCommit6; + using TestControl::factoryRequestList4; + using TestControl::generateDuid; + using TestControl::generateMacAddress; + using TestControl::getNextExchangesNum; + using TestControl::openSocket; + using TestControl::receivePackets; + using TestControl::registerOptionFactories; + using TestControl::sendDiscover4; + using TestControl::sendSolicit6; + using TestControl::setDefaults4; + using TestControl::setDefaults6; + using TestControl::updateSendDue; + + NakedTestControl() : TestControl() { }; + +}; + /// \brief Test Fixture Class /// /// This test fixture class is used to perform @@ -32,36 +68,526 @@ using namespace isc::perfdhcp; class TestControlTest : public virtual ::testing::Test { public: + + typedef std::vector MacAddress; + typedef MacAddress::iterator MacAddressIterator; + + typedef std::vector Duid; + typedef Duid::iterator DuidIterator; + /// \brief Default Constructor TestControlTest() { } -protected: + /// \brief Get local loopback interface name. + /// + /// Scan available network interfaces for local loopback + /// interface and get its name. On Linux this interface is + /// usually called 'lo' but on other systems, e.g. BSD + /// it will have slightly different name. Local loopback + /// interface is required for unit tests that require + /// socket creation. + /// + /// \return local loopback interface name. + std::string getLocalLoopback() const { + const IfaceMgr::IfaceCollection& ifaces = + IfaceMgr::instance().getIfaces(); + for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin(); + iface != ifaces.end(); + ++iface) { + for (IfaceMgr::AddressCollection::const_iterator addr_it = + iface->getAddresses().begin(); + addr_it != iface->getAddresses().end(); + ++addr_it) { + if (asiolink::IOAddress("127.0.0.1").getAddress() == + addr_it->getAddress()) { + return iface->getName(); + } + } + } + return(""); + } + + /// \brief Match requested options in the buffer with given list. + /// + /// This method iterates through options provided in the buffer + /// and matches them with the options specified with first parameter. + /// Options in both vectors may be layed in different order. + /// + /// \param requested_options reference buffer with options. + /// \param buf test buffer with options that will be matched. + /// \return number of options from the buffer matched with options + /// in the reference buffer. + int matchRequestedOptions(const dhcp::OptionBuffer& requested_options, + const dhcp::OptionBuffer& buf) const { + size_t matched_num = 0; + for (size_t i = 0; i < buf.size(); ++i) { + for (int j = 0; j < requested_options.size(); ++j) { + if (requested_options[j] == buf[i]) { + // Requested option has been found. + ++matched_num; + break; + } + } + } + return matched_num; + } + + /// \brief Calculate the maximum vectors' mismatch position. + /// + /// This helper function calculates the maximum mismatch position + /// between two vectors (two different DUIDs or MAC addresses). + /// Calculated position is counted from the end of vectors. + /// Calculation is based on number of simulated clients. When number + /// of clients is less than 256 different DUIDs or MAC addresses can + /// can be coded in such a way that they differ on last vector element. + /// If number of clients is between 257 and 65536 they can differ + /// on two last positions so the returned value will be 2 and so on. + /// + /// \param clients_num number of simulated clinets + /// \param randomization range - for either MAC or DUID it is 6 + /// \return maximum mismatch position + int unequalOctetPosition(const int clients_num, + const size_t random_size) const { + int unequal_pos = 0; + int n = clients_num - 1; + if (n > 0) { + for (int i = 0; i < random_size; ++i) { + if (n < 256) { + unequal_pos = i + 1; + break; + } + n %= 256; + } + } + return unequal_pos; + } + + /// brief Test generation of mulitple DUIDs + /// + /// Thie method checks the generation of multiple DUIDs. Number + /// of iterations depends on the number of simulated clients. + /// It is expected that DUID's size is 14 (consists of DUID-LLT + /// HW type field, 4 octets of time value and MAC address). The + /// MAC address can be randomized depending on the number of + /// simulated clients. The DUID-LLT and HW type are expected to + /// be constant. The time value has to be properly calculated + /// as the number of seconds since DUID time epoch. The parts + /// of MAC address has to change if multiple clients are simulated + /// and do not change if single client is simulated. + void testDuid() const { + int clients_num = CommandOptions::instance().getClientsNum(); + // The old duid will be holding the previously generated DUID. + // It will be used to compare against the new one. If we have + // multiple clients we want to make sure that duids differ. + Duid old_duid(CommandOptions::instance().getDuidPrefix()); + Duid new_duid(0); + // total_dist shows the total difference between generated duid. + // It has to be greater than zero if multiple clients are simulated. + size_t total_dist = 0; + // Holds the position if the octet on which two DUIDS can be different. + // If number of clients is 256 or less it is last DUID octet (except for + // single client when subsequent DUIDs have to be equal). If number of + // clients is between 257 and 65536 the last two octets can differ etc. + const size_t mac_addr_size = 6; + int unequal_pos = unequalOctetPosition(clients_num, mac_addr_size); + + // Initialize Test Control class. + NakedTestControl tc; + // Perform number of iterations to generate number of DUIDs. + // If single clinet is involved, try multiple times (10) and + // see if the same DUID is always generated. + for (int i = 0; i < clients_num * 10; ++i) { + if (new_duid.empty()) { + new_duid = old_duid; + } else { + std::swap(old_duid, new_duid); + new_duid = tc.generateDuid(); + } + // The DUID-LLT is expected to start with DUID_LLT value + // of 1 and hardware ethernet type equal to 1 (HWETHER_TYPE). + const uint8_t duid_llt_and_hw[4] = { 0x0, 0x1, 0x0, 0x1 }; + // We assume DUID-LLT length 14. This includes 4 octets of + // DUID_LLT value, two octets of hardware type, 4 octets + // of time value and 6 octets of variable link layer (MAC) + // address. + const int duid_llt_size = 14; + ASSERT_EQ(duid_llt_size, new_duid.size()); + // The first four octets do not change. + EXPECT_TRUE(std::equal(new_duid.begin(), new_duid.begin() + 4, + duid_llt_and_hw)); + + // As described in RFC3315: 'the time value is the time + // that the DUID is generated represented in seconds + // since midnight (UTC), January 1, 2000, modulo 2^32.' + uint32_t duid_time = 0; + // Pick 4 bytes of the time from generated DUID and put them + // in reverse order (in DUID they are stored in network order). + for (int i = 4; i < 8; ++i) { + duid_time |= new_duid[i] << (i - 4); + } + // Calculate the duration since epoch time. + ptime now = microsec_clock::universal_time(); + ptime duid_epoch(from_iso_string("20000101T000000")); + time_period period(duid_epoch, now); + + // Current time is the same or later than time from the DUID because + // DUID had been generated before reference duration was calculated. + EXPECT_GE(period.length().total_seconds(), duid_time); + + // Get the mismatch position (counting from the end) of + // mismatched octet between previously generated DUID + // and current. + std::pair mismatch_pos = + std::mismatch(old_duid.begin(), old_duid.end(), + new_duid.begin()); + size_t mismatch_dist = + std::distance(mismatch_pos.first, old_duid.end()); + // For single client total_dist is expected to be 0 because + // old_duid and new_duid should always match. If we have + // more clients then duids have to differ except the case + // if randomization algorithm generates the same values but + // this would be an error in randomization algorithm. + total_dist += mismatch_dist; + // Mismatch may have occured on the DUID octet position + // up to calculated earlier unequal_pos. + ASSERT_LE(mismatch_dist, unequal_pos); + } + // If we have more than one client at least one mismatch occured. + if (clients_num > 1) { + EXPECT_GT(total_dist, 0); + } else { + EXPECT_EQ(0, total_dist); + } + } + + /// \brief Test generation of multiple MAC addresses. + /// + /// This method validates generation of multiple MAC addresses. + /// The MAC address can be randomized depending on the number + /// of simulated clients. This test checks if different MAC + /// addresses are generated if number of simulated clients is + /// greater than 1. It also checks if the same MAC addresses is + /// generated if only 1 client is simulated. + void testMacAddress() const { + int clients_num = CommandOptions::instance().getClientsNum(); + // The old_mac will be holding the value of previously generated + // MAC address. We will be comparing the newly generated one with it + // to see if it changes when mulitple clients are simulated or if it + // does not change when single client is simulated. + MacAddress old_mac(CommandOptions::instance().getMacPrefix()); + // Holds the position if the octet on which two MAC addresses can + // be different. If number of clients is 256 or less it is last MAC + // octet (except for single client when subsequent MAC addresses + // have to be equal). If number of clients is between 257 and 65536 + // the last two octets can differ etc. + int unequal_pos = unequalOctetPosition(clients_num, old_mac.size());; + + NakedTestControl tc; + size_t total_dist = 0; + // Do many iterations to generate and test MAC address values. + for (int i = 0; i < clients_num * 10; ++i) { + // Generate new MAC address. + MacAddress new_mac(tc.generateMacAddress()); + // Get the mismatch position (counting from the end) of + // mismatched octet between previously generated MAC address + // and current. + std::pair mismatch_pos = + std::mismatch(old_mac.begin(), old_mac.end(), new_mac.begin()); + size_t mismatch_dist = + std::distance(mismatch_pos.first, old_mac.end()); + // For single client total_dist is expected to be 0 because + // old_mac and new_mac should always match. If we have + // more clients then MAC addresses have to differ except + // the case if randomization algorithm generates the same + // values but this would be an error in randomization algorithm. + total_dist += mismatch_dist; + // Mismatch may have occured on the MAC address'es octet position + // up to calculated earlier unequal_pos. + ASSERT_LE(mismatch_dist, unequal_pos); + } + // If we have more than one client at least one mismatch occured. + if (clients_num > 1) { + EXPECT_GT(total_dist, 0); + } else { + EXPECT_EQ(total_dist, 0); + } + } + + /// \brief Parse command line string with CommandOptions. + /// + /// \param cmdline command line string to be parsed. + /// \throw isc::Unexpected if unexpected error occured. + /// \throw isc::InvalidParameter if command line is invalid. + void processCmdLine(const std::string& cmdline) const { + CommandOptionsHelper::process(cmdline); + } + }; -TEST_F(TestControlTest, Run) { - // Get the instance of TestControl object. - TestControl& test_control = TestControl::instance(); - // Running test without parsing command line arguments is - // expected to cause exception. - EXPECT_THROW(test_control.run(), isc::InvalidOperation); +TEST_F(TestControlTest, GenerateDuid) { + // Simple command line that simulates one client only. Always the + // same DUID will be generated. + ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all")); + testDuid(); - // The command line is to run single test iteration and exit. - // We have to declare argv as const walk around the problem - // of deprecated conversion from string to char*. - const char* argv[] = { "perfdhcp", "-l", "127.0.0.1", "-r", "10", "-n", "1" }; - const int argc = sizeof(argv) / sizeof(argv[0]); + // Simulate 50 clients. Different DUID will be generated. + ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all")); + testDuid(); +} + +TEST_F(TestControlTest, GenerateMacAddress) { + // Simulate one client only. Always the same MAC address will be + // generated. + ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all")); + testMacAddress(); + + // Simulate 50 clients. Different MAC addresses will be generated. + ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -R 50 all")); + testMacAddress(); +} + +TEST_F(TestControlTest, Options4) { + using namespace isc::dhcp; + NakedTestControl tc; + // By default the IP version mode is V4 so there is no need to + // parse command line to override the IP version. Note that + // registerOptionFactories is used for both V4 and V6. + tc.registerOptionFactories(); + // Create option with buffer size equal to 1 and holding DHCPDISCOVER + // message type. + OptionPtr opt_msg_type(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, + OptionBuffer(1, DHCPDISCOVER))); + // Validate the option type and universe. + EXPECT_EQ(Option::V4, opt_msg_type->getUniverse()); + EXPECT_EQ(DHO_DHCP_MESSAGE_TYPE, opt_msg_type->getType()); + // Validate the message type from the option we have now created. + uint8_t msg_type = 0; + ASSERT_NO_THROW(msg_type = opt_msg_type->getUint8()); + EXPECT_EQ(DHCPDISCOVER, msg_type); + + // Create another option: DHCP_PARAMETER_REQUEST_LIST + OptionPtr + opt_requested_options(Option::factory(Option::V4, + DHO_DHCP_PARAMETER_REQUEST_LIST)); + // Here is a list of options that we are requesting in the + // server's response. + const uint8_t requested_options[] = { + DHO_SUBNET_MASK, + DHO_BROADCAST_ADDRESS, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_DOMAIN_NAME, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME + }; + + OptionBuffer + requested_options_ref(requested_options, + requested_options + sizeof(requested_options)); + + // Get the option buffer. It should hold the combination of values + // listed in requested_options array. However their order can be + // different in general so we need to search each value separatelly. + const OptionBuffer& requested_options_buf = + opt_requested_options->getData(); + EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size()); + size_t matched_num = matchRequestedOptions(requested_options_ref, + requested_options_buf); + // We want exactly the same requested options as listed in + // requested_options array - nothing more or less. + EXPECT_EQ(requested_options_ref.size(), matched_num); +} + +TEST_F(TestControlTest, Options6) { + using namespace isc::dhcp; + + // Lets override the IP version to test V6 options (-6 parameter) + ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 -6 all")); + + NakedTestControl tc; + tc.registerOptionFactories(); + + // Validate the D6O_ELAPSED_TIME option. + OptionPtr opt_elapsed_time(Option::factory(Option::V6, D6O_ELAPSED_TIME)); + // Validate the option type and universe. + EXPECT_EQ(Option::V6, opt_elapsed_time->getUniverse()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time->getType()); + // The default value of elapsed time is zero. + uint16_t elapsed_time; + ASSERT_NO_THROW(elapsed_time = opt_elapsed_time->getUint16()); + EXPECT_EQ(0, elapsed_time); + + // With the factory function we may also specify the actual + // value of elapsed time. Let's make use of std::vector + // constructor to create the option buffer, 2 octets long + // with each octet initialized to 0x1. + size_t elapsed_time_buf_size = 2; + uint8_t elapsed_time_pattern = 0x1; + OptionPtr + opt_elapsed_time2(Option::factory(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(elapsed_time_buf_size, + elapsed_time_pattern))); + + // Any buffer that has size neither equal to 0 nor 2 is considered invalid. + elapsed_time_buf_size = 1; + EXPECT_THROW( + Option::factory(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(elapsed_time_buf_size, elapsed_time_pattern)), + isc::BadValue + ); + + // Validate the option type and universe. + EXPECT_EQ(Option::V6, opt_elapsed_time2->getUniverse()); + EXPECT_EQ(D6O_ELAPSED_TIME, opt_elapsed_time2->getType()); + // Make sure the getUint16 does not throw exception. It wile throw + // buffer is shorter than 2 octets. + ASSERT_NO_THROW(elapsed_time = opt_elapsed_time2->getUint16()); + // Check the expected value of elapsed time. + EXPECT_EQ(0x0101, elapsed_time); + + // Validate the D6O_RAPID_COMMIT option. + OptionPtr opt_rapid_commit(Option::factory(Option::V6, D6O_RAPID_COMMIT)); + // Validate the option type and universe. + EXPECT_EQ(Option::V6, opt_rapid_commit->getUniverse()); + EXPECT_EQ(D6O_RAPID_COMMIT, opt_rapid_commit->getType()); + // Rapid commit has no data payload. + EXPECT_THROW(opt_rapid_commit->getUint8(), isc::OutOfRange); + + // Validate the D6O_CLIENTID option. + OptionBuffer duid(CommandOptions::instance().getDuidPrefix()); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + EXPECT_EQ(Option::V6, opt_clientid->getUniverse()); + EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType()); + const OptionBuffer& duid2 = opt_clientid->getData(); + ASSERT_EQ(duid.size(), duid2.size()); + // The Duid we set for option is the same we get. + EXPECT_TRUE(std::equal(duid.begin(), duid.end(), duid2.begin())); + + // Validate the D6O_ORO (Option Request Option). + OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO)); + // Prepare the reference buffer with requested options. + const uint8_t requested_options[] = { + D6O_NAME_SERVERS, + D6O_DOMAIN_SEARCH + }; + OptionBuffer + requested_options_ref(requested_options, + requested_options + sizeof(requested_options)); + // Get the buffer from option. + const OptionBuffer& requested_options_buf = opt_oro->getData(); + // Size of reference buffer and option buffer have to be + // the same for comparison. + EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size()); + // Check if all options in the buffer are matched with reference buffer. + size_t matched_num = matchRequestedOptions(requested_options_ref, + requested_options_buf); + EXPECT_EQ(sizeof(requested_options), matched_num); + + // Validate the D6O_IA_NA option. + OptionPtr opt_ia_na(Option::factory(Option::V6, D6O_IA_NA)); + EXPECT_EQ(Option::V6, opt_ia_na->getUniverse()); + EXPECT_EQ(D6O_IA_NA, opt_ia_na->getType()); + // Every IA_NA option is expected to start with this sequence. + const uint8_t opt_ia_na_array[] = { + 0, 0, 0, 1, // IAID = 1 + 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600 + 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400 + }; + OptionBuffer opt_ia_na_ref(opt_ia_na_array, + opt_ia_na_array + sizeof(opt_ia_na_array)); + const OptionBuffer& opt_ia_na_buf = opt_ia_na->getData(); + ASSERT_EQ(opt_ia_na_buf.size(), opt_ia_na_ref.size()); + EXPECT_TRUE(std::equal(opt_ia_na_ref.begin(), opt_ia_na_ref.end(), + opt_ia_na_buf.begin())); + + // TODO: Add more tests for IA address options. +} + +TEST_F(TestControlTest, Packet4) { + // Use Interface Manager to get the local loopback interface. + // If interface can't be found we don't want to fail test. + std::string loopback_iface(getLocalLoopback()); + if (!loopback_iface.empty()) { + ASSERT_NO_THROW(processCmdLine("perfdhcp -l " + loopback_iface + + " all")); + uint16_t port = 10547; + NakedTestControl tc; + int sock_handle = 0; + // We have to create the socket to setup some parameters of + // outgoing packet. + ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + TestControl::TestControlSocket sock(sock_handle); + uint32_t transid = 123; + boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); + // Set parameters on outgoing packet. + ASSERT_NO_THROW(tc.setDefaults4(sock, pkt4)); + // Validate that packet has been setup correctly. + EXPECT_EQ(loopback_iface, pkt4->getIface()); + EXPECT_EQ(sock.getIfIndex(), pkt4->getIndex()); + EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort()); + EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort()); + EXPECT_EQ(1, pkt4->getHops()); + EXPECT_EQ(asiolink::IOAddress("255.255.255.255"), + pkt4->getRemoteAddr()); + EXPECT_EQ(asiolink::IOAddress(sock.getAddress()), pkt4->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress(sock.getAddress()), pkt4->getGiaddr()); + } else { + std::cout << "Unable to find the loopback interface. Skip test. " + << std::endl; + } +} + +TEST_F(TestControlTest, Packet6) { + // Use Interface Manager to get the local loopback interface. + // If the interface can't be found we don't want to fail test. + std::string loopback_iface(getLocalLoopback()); + if (!loopback_iface.empty()) { + ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface + + " servers")); + uint16_t port = 10547; + NakedTestControl tc; + int sock_handle = 0; + // Create the socket. It will be needed to set packet's + // parameters. + ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + TestControl::TestControlSocket sock(sock_handle); + uint32_t transid = 123; + boost::shared_ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + // Set packet's parameters. + ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6)); + // Validate if parameters have been set correctly. + EXPECT_EQ(loopback_iface, pkt6->getIface()); + EXPECT_EQ(sock.getIfIndex(), pkt6->getIndex()); + EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort()); + EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); + EXPECT_EQ(sock.getAddress(), pkt6->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); + } else { + std::cout << "Unable to find the loopback interface. Skip test. " + << std::endl; + } +} + +TEST_F(TestControlTest, RateControl) { + // We don't specify the exchange rate here so the aggressivity + // value will determine how many packets are to be send each + // time we query the getNextExchangesNum. + ASSERT_NO_THROW(processCmdLine("perfdhcp -l 127.0.0.1 all")); CommandOptions& options = CommandOptions::instance(); - // const_cast is odd but it seems to be the most straight forward way - // to achive the goal. In the future we might think about creating - // a tokenizing function that would dynamically produce non-const - // argv value. - ASSERT_NO_THROW(options.parse(argc, const_cast(argv))); - EXPECT_NO_THROW(test_control.run()); + NakedTestControl tc1; + uint64_t xchgs_num = tc1.getNextExchangesNum(); + EXPECT_EQ(options.getAggressivity(), xchgs_num); - // This is ok to run the test again with the same parameters. - // It may trigger exception if TestControl singleton is in - // invalid state after test run. We want to make sure it is - // safe to rerun the test. - EXPECT_NO_THROW(test_control.run()); + // The exchange rate is now 1 per second. We don't know how many + // exchanges have to initiated exactly but for sure it has to be + // non-zero value. Also, since aggressivity is very high we expect + // that it will not be restricted by aggressivity. + ASSERT_NO_THROW( + processCmdLine("perfdhcp -l 127.0.0.1 -a 1000000 -r 1 all") + ); + NakedTestControl tc2; + xchgs_num = tc2.getNextExchangesNum(); + EXPECT_GT(xchgs_num, 0); + EXPECT_LT(xchgs_num, options.getAggressivity()); } From 00e8a3ebd6c42824b0bfdd0ca96a6acd179a1194 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 16 Aug 2012 17:04:39 +0200 Subject: [PATCH 039/148] [1959] Use StatsMgr to track packet exchanges. --- tests/tools/perfdhcp/stats_mgr.h | 28 ++++--- tests/tools/perfdhcp/test_control.cc | 105 ++++++++++++++++++++++++--- tests/tools/perfdhcp/test_control.h | 33 ++++++++- 3 files changed, 142 insertions(+), 24 deletions(-) diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index 245c69e3cf..7ade910192 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -243,20 +243,21 @@ public: /// In this mode all packets are stored throughout the test execution. ExchangeStats(const ExchangeType xchg_type, const bool archive_enabled) : xchg_type_(xchg_type), - min_delay_(std::numeric_limits::max()), - max_delay_(0.), - sum_delay_(0.), - orphans_(0), - sum_delay_squared_(0.), - ordered_lookups_(0), - unordered_lookup_size_sum_(0), - unordered_lookups_(0), - sent_packets_num_(0), - rcvd_packets_num_(0), sent_packets_(), rcvd_packets_(), archived_packets_(), - archive_enabled_(archive_enabled) { + archive_enabled_(archive_enabled), + min_delay_(std::numeric_limits::max()), + max_delay_(0.), + sum_delay_(0.), + sum_delay_squared_(0.), + orphans_(0), + unordered_lookup_size_sum_(0), + unordered_lookups_(0), + ordered_lookups_(0), + sent_packets_num_(0), + rcvd_packets_num_(0) + { next_sent_ = sent_packets_.begin(); } @@ -555,7 +556,10 @@ public: /// number of dropped packets and number of orphans. void printMainStats() const { using namespace std; - uint64_t drops = getRcvdPacketsNum() - getSentPacketsNum(); + uint64_t drops = 0; + if (getRcvdPacketsNum() >= getSentPacketsNum()) { + drops = getRcvdPacketsNum() - getSentPacketsNum(); + } cout << "sent packets: " << getSentPacketsNum() << endl << "received packets: " << getRcvdPacketsNum() << endl << "drops: " << drops << endl diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 9f4bd5c493..286fc823e7 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -268,6 +268,27 @@ TestControl::getNextExchangesNum() const { return (0); } +void +TestControl::initializeStatsMgr() { + CommandOptions& options = CommandOptions::instance(); + if (options.getIpVersion() == 4) { + stats_mgr4_.reset(); + stats_mgr4_ = StatsMgr4Ptr(new StatsMgr4()); + stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_DO); + if (options.getExchangeMode() == CommandOptions::DO_SA) { + stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RA); + } + + } else if (options.getIpVersion() == 6) { + stats_mgr6_.reset(); + stats_mgr6_ = StatsMgr6Ptr(new StatsMgr6()); + stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_SA); + if (options.getExchangeMode() == CommandOptions::DO_SA) { + stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RR); + } + } +} + int TestControl::openSocket(uint16_t port) const { CommandOptions& options = CommandOptions::instance(); @@ -278,9 +299,9 @@ TestControl::openSocket(uint16_t port) const { IOAddress remoteaddr(servername); if (port == 0) { if (options.getIpVersion() == 6) { - port = 547; - } else if (port == 0) { - port = 67; + port = DHCP6_CLIENT_PORT; + } else if (options.getIpVersion() == 4) { + port = 67; // TODO: find out why port 68 is wrong here. } } if (options.getIpVersion() == 6) { @@ -351,9 +372,59 @@ TestControl::openSocket(uint16_t port) const { } } } + return(sock); } +void +TestControl::printStats() const { + CommandOptions& options = CommandOptions::instance(); + if (options.getIpVersion() == 4) { + if (!stats_mgr4_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " + "hasn't been initialized"); + } + stats_mgr4_->printStats(); + } else if (options.getIpVersion() == 6) { + if (!stats_mgr6_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " + "hasn't been initialized"); + } + stats_mgr6_->printStats(); + } +} + +void +TestControl::receivePacket4(Pkt4Ptr& pkt4) { + switch(pkt4->getType()) { + case DHCPOFFER : + stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO, pkt4); + break; + case DHCPACK : + stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4); + break; + default: + isc_throw(BadValue, "unknown type " << pkt4->getType() + << " of received DHCPv4 packet"); + } +} + +void +TestControl::receivePacket6(Pkt6Ptr& pkt6) { + switch(pkt6->getType()) { + case DHCPV6_ADVERTISE : + stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_SA, pkt6); + break; + case DHCPV6_REPLY : + stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6); + break; + default: + isc_throw(BadValue, "unknown type " << pkt6->getType() + << " of received DHCPv6 packet"); + } + +} + void TestControl::receivePackets() { int timeout = 0; @@ -364,17 +435,17 @@ TestControl::receivePackets() { if (!pkt4) { receiving = false; } else { - // TODO: replace this with use of StatsMgr to increase - // number of received packets. This can be done once - // the 1958 ticket is reviewed and checked-in. - std::cout << "Received packet" << std::endl; + pkt4->unpack(); + receivePacket4(pkt4); } } else if (CommandOptions::instance().getIpVersion() == 6) { Pkt6Ptr pkt6 = IfaceMgr::instance().receive6(timeout); if (!pkt6) { receiving = false; } else { - std::cout << "Received DHCPv6 packet" << std::endl; + if (pkt6->unpack()) { + receivePacket6(pkt6); + } } } } @@ -453,6 +524,8 @@ TestControl::run() { } registerOptionFactories(); TestControlSocket socket(openSocket()); + + initializeStatsMgr(); uint64_t packets_sent = 0; for (;;) { updateSendDue(); @@ -470,9 +543,9 @@ TestControl::run() { sendSolicit6(socket); } ++packets_sent; - cout << "Packets sent " << packets_sent << endl; } } + printStats(); } void @@ -482,7 +555,7 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { // Generate the MAC address to be passed in the packet. std::vector mac_address = generateMacAddress(); // Generate trasnaction id to be set for the new exchange. - const uint32_t transid = static_cast(random()); + const uint32_t transid = static_cast(random() % 0x00FFFFFF); boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); if (!pkt4) { isc_throw(Unexpected, "failed to create DISCOVER packet"); @@ -500,6 +573,11 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { setDefaults4(socket, pkt4); pkt4->pack(); IfaceMgr::instance().send(pkt4); + if (!stats_mgr4_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " + "hasn't been initialized"); + } + stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, pkt4); } void @@ -511,7 +589,7 @@ TestControl::sendSolicit6(const TestControlSocket& socket) { // Generate DUID to be passed to the packet std::vector duid = generateDuid(); // Generate trasnaction id to be set for the new exchange. - const uint32_t transid = static_cast(random()); + const uint32_t transid = static_cast(random() % 0x00FFFFFF); boost::shared_ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); if (!pkt6) { isc_throw(Unexpected, "failed to create SOLICIT packet"); @@ -525,6 +603,11 @@ TestControl::sendSolicit6(const TestControlSocket& socket) { setDefaults6(socket, pkt6); pkt6->pack(); IfaceMgr::instance().send(pkt6); + if (!stats_mgr6_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " + "hasn't been initialized"); + } + stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6); } void diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index de3b942ade..c153fac3b6 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -19,12 +19,15 @@ #include #include +#include #include #include #include #include +#include "stats_mgr.h" + namespace isc { namespace perfdhcp { @@ -44,6 +47,15 @@ namespace perfdhcp { class TestControl : public boost::noncopyable { public: + // Statistics Manager for DHCPv4. + typedef StatsMgr StatsMgr4; + // Pointer to Statistics Manager for DHCPv4; + typedef boost::shared_ptr StatsMgr4Ptr; + // Statictics Manager for DHCPv6. + typedef StatsMgr StatsMgr6; + // Pointer to Statistics Manager for DHCPv6. + typedef boost::shared_ptr StatsMgr6Ptr; + /// \brief Socket wrapper class. /// /// This is wrapper class that holds descriptor of the socket @@ -152,7 +164,6 @@ protected: /// \return true if any of the exit conditions is fulfiled. bool checkExitConditions() const; - /// \brief Factory function to create DHCPv6 ELAPSED_TIME option. /// /// This factory function creates DHCPv6 ELAPSED_TIME option instance. @@ -284,6 +295,12 @@ protected: /// \return number of exchanges to be started immediatelly. uint64_t getNextExchangesNum() const; + /// \brief Initializes Statistics Manager. + /// + /// This function initializes Statistics Manager. If there is + /// the one initialized already it is released. + void initializeStatsMgr(); + /// \brief Open socket to communicate with DHCP server. /// /// Method opens socket and binds it to local address. Function will @@ -305,6 +322,17 @@ protected: /// \return socket descriptor. int openSocket(uint16_t port = 0) const; + /// \brief Print performance statistics. + /// + /// Method prints performance statistics. + /// \throws isc::InvalidOperation if Statistics Manager was + /// not initialized. + void printStats() const; + + void receivePacket4(dhcp::Pkt4Ptr& pkt4); + + void receivePacket6(dhcp::Pkt6Ptr& pkt4); + /// \brief Receive DHCPv4 or DHCPv6 packets from the server. /// /// Method receives DHCPv4 or DHCPv6 packets from the server. @@ -408,6 +436,9 @@ private: boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange /// was initiated. + StatsMgr4Ptr stats_mgr4_; /// Statistics Manager 4. + StatsMgr6Ptr stats_mgr6_; /// Statistics Manager 6. + uint64_t sent_packets_0_; uint64_t sent_packets_1_; }; From fbbae39aea715ccca384083611b6faa8250e068d Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 21 Aug 2012 15:17:14 +0200 Subject: [PATCH 040/148] [1959] Send request messages to server and corresponding unit tests. --- tests/tools/perfdhcp/stats_mgr.h | 75 ++++-- tests/tools/perfdhcp/test_control.cc | 228 ++++++++++++++--- tests/tools/perfdhcp/test_control.h | 132 +++++++++- .../perfdhcp/tests/test_control_unittest.cc | 237 +++++++++++++++++- 4 files changed, 603 insertions(+), 69 deletions(-) diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index 7ade910192..5a3f11445d 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -47,8 +47,8 @@ namespace perfdhcp { /// stored on the list of sent packets. When packets are matched the /// round trip time can be calculated. /// -/// \tparam T class representing DHCPv4 or DHCPv6 packet. -template +/// \param T class representing DHCPv4 or DHCPv6 packet. +template class StatsMgr : public boost::noncopyable { public: @@ -138,7 +138,7 @@ public: /// \param packet packet which transaction id is to be hashed. /// \throw isc::BadValue if packet is null. /// \return transaction id hash. - static uint32_t hashTransid(const boost::shared_ptr& packet) { + static uint32_t hashTransid(const boost::shared_ptr& packet) { if (!packet) { isc_throw(BadValue, "Packet is null"); } @@ -214,12 +214,12 @@ public: /// } /// \endcode typedef boost::multi_index_container< - boost::shared_ptr, + boost::shared_ptr, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::hashed_non_unique< boost::multi_index::global_fun< - const boost::shared_ptr&, + const boost::shared_ptr&, uint32_t, &ExchangeStats::hashTransid > @@ -228,7 +228,7 @@ public: > PktList; /// Packet list iterator for sequencial access to elements. - typedef typename PktList::const_iterator PktListIterator; + typedef typename PktList::iterator PktListIterator; /// Packet list index to search packets using transaction id hash. typedef typename PktList::template nth_index<1>::type PktListTransidHashIndex; @@ -267,7 +267,7 @@ public: /// /// \param packet packet object to be added. /// \throw isc::BadValue if packet is null. - void appendSent(const boost::shared_ptr& packet) { + void appendSent(const boost::shared_ptr& packet) { if (!packet) { isc_throw(BadValue, "Packet is null"); } @@ -281,7 +281,7 @@ public: /// /// \param packet packet object to be added. /// \throw isc::BadValue if packet is null. - void appendRcvd(const boost::shared_ptr& packet) { + void appendRcvd(const boost::shared_ptr& packet) { if (!packet) { isc_throw(BadValue, "Packet is null"); } @@ -297,8 +297,8 @@ public: /// \param rcvd_packet received packet /// \throw isc::BadValue if sent or received packet is null. /// \throw isc::Unexpected if failed to calculate timestamps - void updateDelays(const boost::shared_ptr& sent_packet, - const boost::shared_ptr& rcvd_packet) { + void updateDelays(const boost::shared_ptr& sent_packet, + const boost::shared_ptr& rcvd_packet) { if (!sent_packet) { isc_throw(BadValue, "Sent packet is null"); } @@ -356,7 +356,8 @@ public: /// \throw isc::BadValue if received packet is null. /// \return packet having specified transaction or NULL if packet /// not found - boost::shared_ptr matchPackets(const boost::shared_ptr& rcvd_packet) { + boost::shared_ptr + matchPackets(const boost::shared_ptr& rcvd_packet) { if (!rcvd_packet) { isc_throw(BadValue, "Received packet is null"); } @@ -367,7 +368,7 @@ public: // that the received packet we got has no corresponding // sent packet so orphans counter has to be updated. ++orphans_; - return(boost::shared_ptr()); + return(boost::shared_ptr()); } else if (next_sent_ == sent_packets_.end()) { // Even if there are still many unmatched packets on the // list we might hit the end of it because of unordered @@ -426,13 +427,13 @@ public: // If we are here, it means that both ordered lookup and // unordered lookup failed. Searched packet is not on the list. ++orphans_; - return(boost::shared_ptr()); + return(boost::shared_ptr()); } // Packet is matched so we count it. We don't count unmatched packets // as they are counted as orphans with a separate counter. ++rcvd_packets_num_; - boost::shared_ptr sent_packet(*next_sent_); + boost::shared_ptr sent_packet(*next_sent_); // If packet was found, we assume it will be never searched // again. We want to delete this packet from the list to // improve performance of future searches. @@ -549,6 +550,19 @@ public: /// \return number of received packets. uint64_t getRcvdPacketsNum() const { return(rcvd_packets_num_); } + /// \brief Return number of dropped packets. + /// + /// Method returns number of dropped packets. + /// + /// \return number of dropped packets. + uint64_t getDroppedPacketsNum() const { + uint64_t drops = 0; + if (getSentPacketsNum() > getRcvdPacketsNum()) { + drops = getSentPacketsNum() - getRcvdPacketsNum(); + } + return(drops); + } + /// \brief Print main statistics for packet exchange. /// /// Method prints main statistics for particular exchange. @@ -556,13 +570,9 @@ public: /// number of dropped packets and number of orphans. void printMainStats() const { using namespace std; - uint64_t drops = 0; - if (getRcvdPacketsNum() >= getSentPacketsNum()) { - drops = getRcvdPacketsNum() - getSentPacketsNum(); - } cout << "sent packets: " << getSentPacketsNum() << endl << "received packets: " << getRcvdPacketsNum() << endl - << "drops: " << drops << endl + << "drops: " << getDroppedPacketsNum() << endl << "orphans: " << getOrphans() << endl; } @@ -614,7 +624,7 @@ public: for (PktListIterator it = rcvd_packets_.begin(); it != rcvd_packets_.end(); ++it) { - boost::shared_ptr rcvd_packet = *it; + boost::shared_ptr rcvd_packet = *it; PktListTransidHashIndex& idx = archived_packets_.template get<1>(); std::pairgetTransid() == rcvd_packet->getTransid()) { - boost::shared_ptr sent_packet = *it_archived; + boost::shared_ptr sent_packet = *it_archived; // Get sent and received packet times. ptime sent_time = sent_packet->getTimestamp(); ptime rcvd_time = rcvd_packet->getTimestamp(); @@ -839,7 +849,7 @@ public: /// \throw isc::BadValue if invalid exchange type specified or /// packet is null. void passSentPacket(const ExchangeType xchg_type, - const boost::shared_ptr& packet) { + const boost::shared_ptr& packet) { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type); xchg_stats->appendSent(packet); } @@ -857,10 +867,11 @@ public: /// or packet is null. /// \throw isc::Unexpected if corresponding packet was not /// found on the list of sent packets. - void passRcvdPacket(const ExchangeType xchg_type, - const boost::shared_ptr& packet) { + boost::shared_ptr + passRcvdPacket(const ExchangeType xchg_type, + const boost::shared_ptr& packet) { ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type); - boost::shared_ptr sent_packet + boost::shared_ptr sent_packet = xchg_stats->matchPackets(packet); if (sent_packet) { @@ -869,6 +880,7 @@ public: xchg_stats->appendRcvd(packet); } } + return(sent_packet); } /// \brief Return minumum delay between sent and received packet. @@ -1003,6 +1015,19 @@ public: return(xchg_stats->getRcvdPacketsNum()); } + /// \brief Return total number of dropped packets. + /// + /// Method returns total number of dropped packets for specified + /// exchange type. + /// + /// \param xchg_type exchange type. + /// \throw isc::BadValue if invalid exchange type specified. + /// \return number of dropped packets. + uint64_t getDroppedPacketsNum(const ExchangeType xchg_type) const { + ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type); + return(xchg_stats->getDroppedPacketsNum()); + } + /// \brief Return name of the exchange. /// /// Method returns name of the specified exchange type. diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 286fc823e7..87b2814c84 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -80,18 +80,104 @@ TestControl::instance() { TestControl::TestControl() : send_due_(microsec_clock::universal_time()), - last_sent_(send_due_) { + last_sent_(send_due_), + transid_gen_(new TransidGenerator()) { } bool TestControl::checkExitConditions() const { CommandOptions& options = CommandOptions::instance(); - if ((options.getNumRequests().size() > 0) && - (sent_packets_0_ >= options.getNumRequests()[0])) { - return(true); - } else if ((options.getNumRequests().size() == 2) && - (sent_packets_1_ >= options.getNumRequests()[1])) { - return(true); + // Check if we reached maximum number of DISCOVER/SOLICIT sent. + if (options.getNumRequests().size() > 0) { + if (options.getIpVersion() == 4) { + if (getSentPacketsNum(StatsMgr4::XCHG_DO) >= + options.getNumRequests()[0]) { + return(true); + } + } else if (options.getIpVersion() == 6) { + if (stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA) >= + options.getNumRequests()[0]) { + return(true); + } + } + } + // Check if we reached maximum number REQUEST packets. + if (options.getNumRequests().size() == 2) { + if (options.getIpVersion() == 4) { + if (stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) >= + options.getNumRequests()[1]) { + return(true); + } + } else if (options.getIpVersion() == 6) { + if (stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) >= + options.getNumRequests()[1]) { + return(true); + } + } + } + // Check if we reached maximum number of drops of OFFER/ADVERTISE packets. + if (options.getMaxDrop().size() > 0) { + if (options.getIpVersion() == 4) { + if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_DO) >= + options.getMaxDrop()[0]) { + return(true); + } + } else if (options.getIpVersion() == 6) { + if (stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_SA) >= + options.getMaxDrop()[0]) { + return(true); + } + } + } + // Check if we reached maximum number of drops of ACK/REPLY packets. + if (options.getMaxDrop().size() == 2) { + if (options.getIpVersion() == 4) { + if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) >= + options.getMaxDrop()[1]) { + return(true); + } + } else if (options.getIpVersion() == 6) { + if (stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) >= + options.getMaxDrop()[1]) { + return(true); + } + } + } + // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets. + if (options.getMaxDropPercentage().size() > 0) { + if (options.getIpVersion() == 4) { + if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_DO) > 10) && + ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_DO) / + stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_DO)) >= + options.getMaxDropPercentage()[0])) { + return(true); + } + } else if (options.getIpVersion() == 6) { + if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA) > 10) && + ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_SA) / + stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA)) >= + options.getMaxDropPercentage()[0])) { + return(true); + } + } + } + // Check if we reached maximum drops percentage of ACK/REPLY packets. + if (options.getMaxDropPercentage().size() == 2) { + if (options.getIpVersion() == 4) { + if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) > 10) && + ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) / + stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA)) >= + options.getMaxDropPercentage()[0])) { + return(true); + } + } else if (options.getIpVersion() == 6) { + if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) > 10) && + ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) / + stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR)) >= + options.getMaxDropPercentage()[0])) { + return(true); + } + } } return(false); } @@ -170,8 +256,6 @@ TestControl::factoryRequestList4(Option::Universe u, return opt; } - - std::vector TestControl::generateMacAddress() const { CommandOptions& options = CommandOptions::instance(); @@ -268,6 +352,26 @@ TestControl::getNextExchangesNum() const { return (0); } +uint64_t +TestControl::getRcvdPacketsNum(const ExchangeType xchg_type) const { + uint8_t ip_version = CommandOptions::instance().getIpVersion(); + if (ip_version == 4) { + return(stats_mgr4_->getRcvdPacketsNum(xchg_type)); + } + return(stats_mgr6_-> + getRcvdPacketsNum(static_cast(xchg_type))); +} + +uint64_t +TestControl::getSentPacketsNum(const ExchangeType xchg_type) const { + uint8_t ip_version = CommandOptions::instance().getIpVersion(); + if (ip_version == 4) { + return(stats_mgr4_->getSentPacketsNum(xchg_type)); + } + return(stats_mgr6_-> + getSentPacketsNum(static_cast(xchg_type))); +} + void TestControl::initializeStatsMgr() { CommandOptions& options = CommandOptions::instance(); @@ -275,7 +379,7 @@ TestControl::initializeStatsMgr() { stats_mgr4_.reset(); stats_mgr4_ = StatsMgr4Ptr(new StatsMgr4()); stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_DO); - if (options.getExchangeMode() == CommandOptions::DO_SA) { + if (options.getExchangeMode() == CommandOptions::DORA_SARR) { stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RA); } @@ -283,9 +387,9 @@ TestControl::initializeStatsMgr() { stats_mgr6_.reset(); stats_mgr6_ = StatsMgr6Ptr(new StatsMgr6()); stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_SA); - if (options.getExchangeMode() == CommandOptions::DO_SA) { + if (options.getExchangeMode() == CommandOptions::DORA_SARR) { stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RR); - } + } } } @@ -395,7 +499,8 @@ TestControl::printStats() const { } void -TestControl::receivePacket4(Pkt4Ptr& pkt4) { +TestControl::receivePacket4(const TestControlSocket&, + const Pkt4Ptr& pkt4) { switch(pkt4->getType()) { case DHCPOFFER : stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO, pkt4); @@ -410,23 +515,25 @@ TestControl::receivePacket4(Pkt4Ptr& pkt4) { } void -TestControl::receivePacket6(Pkt6Ptr& pkt6) { - switch(pkt6->getType()) { - case DHCPV6_ADVERTISE : - stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_SA, pkt6); - break; - case DHCPV6_REPLY : +TestControl::receivePacket6(const TestControlSocket& socket, + const Pkt6Ptr& pkt6) { + uint8_t packet_type = pkt6->getType(); + if (packet_type == DHCPV6_ADVERTISE) { + Pkt6Ptr solicit_pkt6(stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_SA, + pkt6)); + if (solicit_pkt6) { + sendRequest6(socket, solicit_pkt6, pkt6); + } + } else if (packet_type == DHCPV6_REPLY) { stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6); - break; - default: + } else { isc_throw(BadValue, "unknown type " << pkt6->getType() << " of received DHCPv6 packet"); } - } void -TestControl::receivePackets() { +TestControl::receivePackets(const TestControlSocket& socket) { int timeout = 0; bool receiving = true; while (receiving) { @@ -436,7 +543,7 @@ TestControl::receivePackets() { receiving = false; } else { pkt4->unpack(); - receivePacket4(pkt4); + receivePacket4(socket, pkt4); } } else if (CommandOptions::instance().getIpVersion() == 6) { Pkt6Ptr pkt6 = IfaceMgr::instance().receive6(timeout); @@ -444,7 +551,7 @@ TestControl::receivePackets() { receiving = false; } else { if (pkt6->unpack()) { - receivePacket6(pkt6); + receivePacket6(socket, pkt6); } } } @@ -524,7 +631,7 @@ TestControl::run() { } registerOptionFactories(); TestControlSocket socket(openSocket()); - + initializeStatsMgr(); uint64_t packets_sent = 0; for (;;) { @@ -534,7 +641,7 @@ TestControl::run() { } uint64_t packets_due = getNextExchangesNum(); - receivePackets(); + receivePackets(socket); for (uint64_t i = packets_due; i > 0; --i) { if (options.getIpVersion() == 4) { @@ -555,8 +662,8 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { // Generate the MAC address to be passed in the packet. std::vector mac_address = generateMacAddress(); // Generate trasnaction id to be set for the new exchange. - const uint32_t transid = static_cast(random() % 0x00FFFFFF); - boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); + const uint32_t transid = generateTransid(); + Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); if (!pkt4) { isc_throw(Unexpected, "failed to create DISCOVER packet"); } @@ -580,6 +687,59 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, pkt4); } +void +TestControl::sendRequest6(const TestControlSocket& socket, + const Pkt6Ptr& solicit_pkt6, + const Pkt6Ptr& advertise_pkt6) { + const uint32_t transid = static_cast(random() % 0x00FFFFFF); + Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid)); + // Calculate elapsed time + ptime solicit_time = solicit_pkt6->getTimestamp(); + ptime advertise_time = advertise_pkt6->getTimestamp(); + if (solicit_time.is_not_a_date_time()) { + isc_throw(Unexpected, "timestamp was not set for SOLICIT packet"); + } + if (advertise_time.is_not_a_date_time()) { + isc_throw(Unexpected, "timestamp was not set for ADVERTISE packet"); + } + time_period period(solicit_time, advertise_time); + if (period.is_null()) { + pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME)); + } else { + OptionBuffer buf(); + const uint32_t elapsed_time = period.length().total_seconds(); + OptionPtr opt_elapsed_time = + Option::factory(Option::V6, D6O_ELAPSED_TIME); + opt_elapsed_time->setUint16(static_cast(elapsed_time)); + pkt6->addOption(opt_elapsed_time); + } + OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID); + if (!opt_clientid) { + isc_throw(Unexpected, "client id not found in received packet"); + } + pkt6->addOption(opt_clientid); + OptionPtr opt_serverid = advertise_pkt6->getOption(D6O_SERVERID); + if (!opt_serverid) { + isc_throw(Unexpected, "server id not found in received packet"); + } + pkt6->addOption(opt_serverid); + OptionPtr opt_ia_na = advertise_pkt6->getOption(D6O_IA_NA); + if (!opt_ia_na) { + isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received " + "packet"); + } + pkt6->addOption(opt_ia_na); + setDefaults6(socket, pkt6); + + pkt6->pack(); + IfaceMgr::instance().send(pkt6); + if (!stats_mgr6_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " + "hasn't been initialized"); + } + stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RR, pkt6); +} + void TestControl::sendSolicit6(const TestControlSocket& socket) { ++sent_packets_0_; @@ -589,13 +749,13 @@ TestControl::sendSolicit6(const TestControlSocket& socket) { // Generate DUID to be passed to the packet std::vector duid = generateDuid(); // Generate trasnaction id to be set for the new exchange. - const uint32_t transid = static_cast(random() % 0x00FFFFFF); - boost::shared_ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); + const uint32_t transid = generateTransid(); + Pkt6Ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); if (!pkt6) { isc_throw(Unexpected, "failed to create SOLICIT packet"); } pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME)); - pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT)); + // pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT)); pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid)); pkt6->addOption(Option::factory(Option::V6, D6O_ORO)); pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA)); @@ -612,7 +772,7 @@ TestControl::sendSolicit6(const TestControlSocket& socket) { void TestControl::setDefaults4(const TestControlSocket& socket, - const boost::shared_ptr& pkt) { + const Pkt4Ptr& pkt) { CommandOptions& options = CommandOptions::instance(); // Interface name. pkt->setIface(socket.getIface()); @@ -634,7 +794,7 @@ TestControl::setDefaults4(const TestControlSocket& socket, void TestControl::setDefaults6(const TestControlSocket& socket, - const boost::shared_ptr& pkt) { + const Pkt6Ptr& pkt) { CommandOptions& options = CommandOptions::instance(); // Interface name. pkt->setIface(socket.getIface()); diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index c153fac3b6..1a3157b3e3 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -55,6 +56,8 @@ public: typedef StatsMgr StatsMgr6; // Pointer to Statistics Manager for DHCPv6. typedef boost::shared_ptr StatsMgr6Ptr; + // Packet exchange type. + typedef StatsMgr<>::ExchangeType ExchangeType; /// \brief Socket wrapper class. /// @@ -120,6 +123,26 @@ public: asiolink::IOAddress addr_; ///< Address bound. }; + /// \brief Default transaction id generator class. + /// + /// This is default transaction id generator class. The member + /// function is used to generate unique transaction id value. + /// Other generator classes should derive from this one to + /// override the standard generation algorithm (e.g. unit tests + /// override this class wih algorithm that produces more predictable + /// transaction id values). + class TransidGenerator { + public: + /// \brief generate transaction id. + /// + /// \return generated transazction id value. + virtual uint32_t generate() { + return static_cast(random() % 0x00FFFFFF); + } + }; + + typedef boost::shared_ptr TransidGeneratorPtr; + /// \brief Length of the Ethernet HW address (MAC) in bytes. static const uint8_t HW_ETHER_LEN = 6; @@ -129,7 +152,7 @@ public: /// \return the only existing instance of test control static TestControl& instance(); - /// Run performance test. + /// brief\ Run performance test. /// /// Method runs whole performance test. Command line options must /// be parsed prior to running this function. Othewise function will @@ -139,6 +162,14 @@ public: /// \throw isc::Unexpected if internal Test Controler error occured. void run(); + /// \brief Set new transaction id generator. + /// + /// \param generator generator object to be used. + void setTransidGenerator(TransidGeneratorPtr& generator) { + transid_gen_.reset(); + transid_gen_ = generator; + } + protected: // We would really like these methods and members to be private but @@ -285,6 +316,13 @@ protected: /// \return generated MAC address. std::vector generateMacAddress() const; + /// \brief generate transaction id. + /// + /// \return generated transaction id. + uint32_t generateTransid() { + return(transid_gen_->generate()); + } + /// \brief Returns number of exchanges to be started. /// /// Method returns number of new exchanges to be started as soon @@ -329,14 +367,45 @@ protected: /// not initialized. void printStats() const; - void receivePacket4(dhcp::Pkt4Ptr& pkt4); + /// \brief Receive DHCPv4 packet. + /// + /// Method performs reception of the DHCPv4 packet, updates + /// statistics and responsds to the server if required, e.g. + /// when OFFER packet arrives, this function will initiate + /// REQUEST message to the server. + /// + /// \param socket socket to be used. + /// \param pkt4 object representing DHCPv4 packet received. + /// \throw isc::BadValue if unknown message type received. + /// \throw isc::Unexpected if unexpected error occured. + void receivePacket4(const TestControlSocket& socket, + const dhcp::Pkt4Ptr& pkt4); - void receivePacket6(dhcp::Pkt6Ptr& pkt4); + /// \brief Receive DHCPv6 packet. + /// + /// Method performs reception of the DHCPv6 packet, updates + /// statistics and responsds to the server if required, e.g. + /// when ADVERTISE packet arrives, this function will initiate + /// REQUEST message to the server. + /// + /// \param socket socket to be used. + /// \param pkt6 object representing DHCPv6 packet received. + /// \throw isc::BadValue if unknown message type received. + /// \throw isc::Unexpected if unexpected error occured. + void receivePacket6(const TestControlSocket& socket, + const dhcp::Pkt6Ptr& pkt6); /// \brief Receive DHCPv4 or DHCPv6 packets from the server. /// /// Method receives DHCPv4 or DHCPv6 packets from the server. - void receivePackets(); + /// This function will call \ref receivePacket4 or + /// \ref receivePacket6 depending if DHCPv4 or DHCPv6 packet + /// has arrived. + /// + /// \param socket socket to be used. + /// \throw::BadValue if unknown message type received. + /// \throw::Unexpected if unexpected error occured. + void receivePackets(const TestControlSocket& socket); /// \brief Register option factory functions for DHCPv4 /// @@ -378,6 +447,28 @@ protected: /// \throw isc::BadValue if MAC address has invalid length. void sendDiscover4(const TestControlSocket& socket); + /// \brief Sent DHCPv6 REQUEST message. + /// + /// Method creates and sends DHCPv6 REQUEST message to the server + /// with the following options: + /// - D6O_ELAPSED_TIME + /// - D6O_CLIENTID + /// - D6O_SERVERID + /// The elapsed time is calculated based on the duration between + /// sending a SOLICIT and receiving the ADVERTISE packet prior. + /// For this reason both solicit and advertise packet objects have + /// to be passed when calling this function. + /// + /// \param socket socket to be used to send message. + /// \param solicit_pkt6 SOLICIT packet object. + /// \param advertise_pkt6 ADVERTISE packet object. + /// \throw isc::Unexpected if unexpected error occured. + /// \throw isc::InvalidOperation if Statistics Manager has not been + /// initialized. + void sendRequest6(const TestControlSocket& socket, + const dhcp::Pkt6Ptr& solicit_pkt6, + const dhcp::Pkt6Ptr& advertise_pkt6); + /// \brief Send DHCPv6 SOLICIT message. /// /// Method creates and sends DHCPv6 SOLICIT message to the server @@ -405,7 +496,7 @@ protected: /// \param socket socket used to send the packet. /// \param pkt reference to packet to be configured. void setDefaults4(const TestControlSocket& socket, - const boost::shared_ptr& pkt); + const dhcp::Pkt4Ptr& pkt); /// \brief Set default DHCPv6 packet parameters. /// @@ -420,7 +511,7 @@ protected: /// \param socket socket used to send the packet. /// \param pkt reference to packet to be configured. void setDefaults6(const TestControlSocket& socket, - const boost::shared_ptr& pkt); + const dhcp::Pkt6Ptr& pkt); /// \brief Update due time to initiate next chunk of exchanges. /// @@ -431,13 +522,38 @@ protected: private: + /// \brief Generate transaction id using random function. + /// + /// \return generated transaction id value. + static uint32_t generateTransidRandom(); + + /// \brief Get number of received packets. + /// + /// Get the number of received packets from the Statistics Manager. + /// Function may throw if Statistics Manager object is not + /// initialized. + /// \param xchg_type packet exchange type. + /// \return number of received packets. + uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const; + + /// \brief Get number of sent packets. + /// + /// Get the number of sent packets from the Statistics Manager. + /// Function may throw if Statistics Manager object is not + /// initialized. + /// \param xchg_type packet exchange type. + /// \return number of sent packets. + uint64_t getSentPacketsNum(const ExchangeType xchg_type) const; + boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk ///< of exchanges. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange /// was initiated. + StatsMgr4Ptr stats_mgr4_; ///< Statistics Manager 4. + StatsMgr6Ptr stats_mgr6_; ///< Statistics Manager 6. - StatsMgr4Ptr stats_mgr4_; /// Statistics Manager 4. - StatsMgr6Ptr stats_mgr6_; /// Statistics Manager 6. + // Pointers to functions. + TransidGeneratorPtr transid_gen_; ///< Transaction id generator. uint64_t sent_packets_0_; uint64_t sent_packets_1_; diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index aa8983051e..52c55b2f10 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -38,6 +38,34 @@ using namespace isc::perfdhcp; /// to allow unit testing. class NakedTestControl: public TestControl { public: + + /// \brief Incremental transaction id generaator. + /// + /// This is incremental transaction id generator. It overrides + /// the default transaction id generator that generates transaction + /// ids using random function. This generator will generate values + /// like: 1,2,3 etc. + class IncrementalGenerator : public TestControl::TransidGenerator { + public: + /// \brief Default constructor. + IncrementalGenerator() : + TransidGenerator(), + transid_(0) { + } + + /// \brief Generate unique transaction id. + /// + /// Generate unique transaction ids incrementally: + /// 1,2,3,4 etc. + /// + /// \return generated transaction id. + virtual uint32_t generate() { + return ++transid_; + } + private: + uint32_t transid_; ///< Last generated transaction id. + }; + using TestControl::checkExitConditions; using TestControl::factoryElapsedTime6; using TestControl::factoryGeneric; @@ -48,14 +76,15 @@ public: using TestControl::generateDuid; using TestControl::generateMacAddress; using TestControl::getNextExchangesNum; + using TestControl::initializeStatsMgr; using TestControl::openSocket; - using TestControl::receivePackets; + using TestControl::receivePacket4; + using TestControl::receivePacket6; using TestControl::registerOptionFactories; using TestControl::sendDiscover4; using TestControl::sendSolicit6; using TestControl::setDefaults4; using TestControl::setDefaults6; - using TestControl::updateSendDue; NakedTestControl() : TestControl() { }; @@ -78,6 +107,11 @@ public: /// \brief Default Constructor TestControlTest() { } + static uint32_t generateTransidIncremental() { + static uint32_t transid(1); + return ++transid; + } + /// \brief Get local loopback interface name. /// /// Scan available network interfaces for local loopback @@ -260,6 +294,107 @@ public: } } + /// \brief Test DHCPv4 exchanges. + /// + /// Function simulates DHCPv4 exchanges. Function caller specifies + /// number of exchanges to be simulated and number of simulated + /// responses. When number of responses is lower than number of + /// iterations than the difference between them is the number + /// of simulated packet drops. This is useful to test if program + /// exit conditions are handled properly (maximum number of packet + /// drops specified as -D is taken into account). + /// + /// \param iterations_num number of exchanges to simulate. + /// \param receive_num number of received OFFER packets. + /// \param iterations_performed actual number of iterations. + void testPkt4Exchange(int iterations_num, + int receive_num, + int& iterations_performed) const { + uint16_t port = 10547; + int sock_handle = 0; + NakedTestControl tc; + tc.initializeStatsMgr(); + // Incremental transaction id generator will generate + // predictable values of transaction id for each iteration. + // This is important because we need to simulate reponses + // from the server and use the same transaction ids as in + // packets sent by client. + TestControl::TransidGeneratorPtr + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + // Socket is needed to send packets through the interface. + ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + TestControl::TestControlSocket sock(sock_handle); + int i = 0; + for (; i < iterations_num; ++i) { + if (tc.checkExitConditions()) { + break; + } + ASSERT_NO_THROW(tc.sendDiscover4(sock)); + // Do not simulate responses for packets later + // that specified as receive_num. This simulates + // packet drops. + if (i - 1 < receive_num) { + boost::shared_ptr offer_pkt4(createOfferPkt4(i)); + // Receive OFFER and send REQUEST. + ASSERT_NO_THROW(tc.receivePacket4(sock, offer_pkt4)); + } + } + // Return the number of iterations performed. + iterations_performed = i; + } + + /// \brief Test DHCPv6 exchanges. + /// + /// Function simulates DHCPv6 exchanges. Function caller specifies + /// number of exchanges to be simulated and number of simulated + /// responses. When number of responses is lower than number of + /// iterations than the difference between them is the number + /// of simulated packet drops. This is useful to test if program + /// exit conditions are handled properly (maximum number of packet + /// drops specified as -D is taken into account). + /// + /// \param iterations_num number of exchanges to simulate. + /// \param receive_num number of received OFFER packets. + /// \param iterations_performed actual number of iterations. + void testPkt6Exchange(int iterations_num, + int receive_num, + int& iterations_performed) const { + uint16_t port = 10547; + int sock_handle = 0; + NakedTestControl tc; + tc.initializeStatsMgr(); + // Incremental transaction id generator will generate + // predictable values of transaction id for each iteration. + // This is important because we need to simulate reponses + // from the server and use the same transaction ids as in + // packets sent by client. + TestControl::TransidGeneratorPtr + generator(new NakedTestControl::IncrementalGenerator()); + tc.setTransidGenerator(generator); + // Socket is needed to send packets through the interface. + ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + TestControl::TestControlSocket sock(sock_handle); + int i = 0; + for (; i < iterations_num; ++i) { + if (tc.checkExitConditions()) { + break; + } + // Do not simulate responses for packets later + // that specified as receive_num. This simulates + // packet drops. + ASSERT_NO_THROW(tc.sendSolicit6(sock)); + if (i - 1 < receive_num) { + boost::shared_ptr advertise_pkt6(createAdvertisePkt6(i)); + // Receive ADVERTISE and send REQUEST. + ASSERT_NO_THROW(tc.receivePacket6(sock, advertise_pkt6)); + } + + } + // Return the number of iterations performed. + iterations_performed = i; + } + /// \brief Test generation of multiple MAC addresses. /// /// This method validates generation of multiple MAC addresses. @@ -322,6 +457,33 @@ public: CommandOptionsHelper::process(cmdline); } +private: + boost::shared_ptr + createOfferPkt4(uint32_t transid) const { + boost::shared_ptr offer(new Pkt4(DHCPOFFER, transid)); + OptionPtr opt_msg_type = Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, + OptionBuffer(DHCPOFFER)); + offer->setYiaddr(asiolink::IOAddress("127.0.0.1")); + offer->addOption(opt_msg_type); + offer->updateTimestamp(); + return(offer); + } + + boost::shared_ptr + createAdvertisePkt6(uint32_t transid) const { + OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); + OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID)); + NakedTestControl tc; + std::vector duid(tc.generateDuid()); + OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); + boost::shared_ptr advertise(new Pkt6(DHCPV6_ADVERTISE, transid)); + advertise->addOption(opt_ia_na); + advertise->addOption(opt_serverid); + advertise->addOption(opt_clientid); + advertise->updateTimestamp(); + return(advertise); + } + }; TEST_F(TestControlTest, GenerateDuid) { @@ -568,6 +730,77 @@ TEST_F(TestControlTest, Packet6) { } } +TEST_F(TestControlTest, Packet4Exchange) { + // Get the local loopback interface to open socket on + // it and test packets exchanges. We don't want to fail + // the test if interface is not available. + std::string loopback_iface(getLocalLoopback()); + if (loopback_iface.empty()) { + std::cout << "Unable to find the loopback interface. Skip test." + << std::endl; + return; + } + + // Set number of iterations to some high value. + const int iterations_num = 100; + processCmdLine("perfdhcp -l " + loopback_iface + + " -r 100 -n 10 -R 20 127.0.0.1"); + // The actual number of iterations will be stored in the + // following variable. + int iterations_performed = 0; + testPkt4Exchange(iterations_num, iterations_num, iterations_performed); + // The command line restricts the number of iterations to 10 + // with -n 10 parameter. + EXPECT_EQ(10, iterations_performed); + + // With the following command line we restrict the maximum + // number of dropped packets to 20% of all. + processCmdLine("perfdhcp -l " + loopback_iface + + " -r 100 -R 20 -n 20 -D 10% 127.0.0.1"); + // The number iterations is restricted by the percentage of + // dropped packets (-D 10%). We also have to bump up the number + // of iterations because the percentage limitation checks starts + // at packet #10. We expect that at packet #12 the 10% threshold + // will be reached. + const int received_num = 10; + testPkt4Exchange(iterations_num, received_num, iterations_performed); + EXPECT_EQ(12, iterations_performed); +} + +TEST_F(TestControlTest, Packet6Exchange) { + // Get the local loopback interface to open socket on + // it and test packets exchanges. We don't want to fail + // the test if interface is not available. + std::string loopback_iface(getLocalLoopback()); + if (loopback_iface.empty()) { + std::cout << "Unable to find the loopback interface. Skip test." + << std::endl; + return; + } + + const int iterations_num = 100; + // Set number of iterations to 10. + processCmdLine("perfdhcp -l " + loopback_iface + + " -6 -r 100 -n 10 -R 20 ::1"); + int iterations_performed = 0; + // Set number of received packets equal to number of iterations. + // This simulates no packet drops. + testPkt6Exchange(iterations_num, iterations_num, iterations_performed); + // Actual number of iterations should be 10. + EXPECT_EQ(10, iterations_performed); + + // The maximum number of dropped packets is 3 (because of -D 3). + processCmdLine("perfdhcp -l " + loopback_iface + + " -6 -r 100 -n 10 -R 20 -D 3 ::1"); + // For the first 3 packets we are simulating responses from server. + // For other packets we don't so packet as 4,5,6 will be dropped and + // then test should be interrupted and actual number of iterations will + // be 6. + const int received_num = 3; + testPkt6Exchange(iterations_num, received_num, iterations_performed); + EXPECT_EQ(6, iterations_performed); +} + TEST_F(TestControlTest, RateControl) { // We don't specify the exchange rate here so the aggressivity // value will determine how many packets are to be send each From 3e6ed8d54322d7ebeb2721664dd7d2dd8326094a Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 21 Aug 2012 17:18:30 +0200 Subject: [PATCH 041/148] [1959] Print overall rate statistics. --- tests/tools/perfdhcp/stats_mgr.h | 19 ++++++++++++++++++- tests/tools/perfdhcp/test_control.cc | 23 +++++++++++++++++++++++ tests/tools/perfdhcp/test_control.h | 5 +++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index 5a3f11445d..1e57dda15b 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -775,7 +775,8 @@ public: StatsMgr(const bool archive_enabled = false) : exchanges_(), custom_counters_(), - archive_enabled_(archive_enabled) { + archive_enabled_(archive_enabled), + boot_time_(boost::posix_time::microsec_clock::universal_time()) { } /// \brief Specify new exchange type. @@ -1028,6 +1029,20 @@ public: return(xchg_stats->getDroppedPacketsNum()); } + /// \brief Get time period since the start of test. + /// + /// Calculate dna return period since the test start. This + /// can be specifically helpful when calculating packet + /// exchange rates. + /// + /// \return test period so far. + boost::posix_time::time_period getTestPeriod() const { + using namespace boost::posix_time; + time_period test_period(boot_time_, + microsec_clock::universal_time()); + return test_period; + } + /// \brief Return name of the exchange. /// /// Method returns name of the specified exchange type. @@ -1158,6 +1173,8 @@ private: /// for extended period of time and many packets have to be /// archived. bool archive_enabled_; + + boost::posix_time::ptime boot_time_; ///< Time when test is started. }; } // namespace perfdhcp diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 87b2814c84..9ba869ac33 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -480,8 +480,31 @@ TestControl::openSocket(uint16_t port) const { return(sock); } +void +TestControl::printRate() const { + double rate = 0; + CommandOptions& options = CommandOptions::instance(); + if (options.getIpVersion() == 4) { + double duration = + stats_mgr4_->getTestPeriod().length().total_nanoseconds() / 1e9; + rate = stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) / duration; + } else if (options.getIpVersion() == 6) { + double duration = + stats_mgr6_->getTestPeriod().length().total_nanoseconds() / 1e9; + rate = stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) / duration; + } + std::cout << "***Rate statistics***" << std::endl; + if (options.getRate() > 0) { + std::cout << "Rate: " << rate << ", expected rate: " + << options.getRate() << std::endl << std::endl; + } else { + std::cout << "Rate: " << rate << std::endl << std::endl; + } +} + void TestControl::printStats() const { + printRate(); CommandOptions& options = CommandOptions::instance(); if (options.getIpVersion() == 4) { if (!stats_mgr4_) { diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 1a3157b3e3..a93d05dfc2 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -360,6 +360,11 @@ protected: /// \return socket descriptor. int openSocket(uint16_t port = 0) const; + /// \brief Print rate statistics. + /// + /// Method print packet exchange rate statistics. + void printRate() const; + /// \brief Print performance statistics. /// /// Method prints performance statistics. From 61f144876b5c42de12b51fc79ea2f6b0544001ce Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 24 Aug 2012 13:18:41 +0200 Subject: [PATCH 042/148] [1959] Implemented most of the command line options. --- tests/tools/perfdhcp/test_control.cc | 205 +++++++++++++++--- tests/tools/perfdhcp/test_control.h | 45 +++- .../perfdhcp/tests/test_control_unittest.cc | 71 +++--- 3 files changed, 246 insertions(+), 75 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 9ba869ac33..42058a9adb 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -78,15 +78,27 @@ TestControl::instance() { return (test_control); } -TestControl::TestControl() : - send_due_(microsec_clock::universal_time()), - last_sent_(send_due_), - transid_gen_(new TransidGenerator()) { +TestControl::TestControl() { + reset(); } bool TestControl::checkExitConditions() const { CommandOptions& options = CommandOptions::instance(); + // Check if test period passed.. + if (options.getPeriod() != 0) { + if (options.getIpVersion() == 4) { + time_period period(stats_mgr4_->getTestPeriod()); + if (period.length().total_seconds() >= options.getPeriod()) { + return true; + } + } else if (options.getIpVersion() == 6) { + time_period period = stats_mgr6_->getTestPeriod(); + if (period.length().total_seconds() >= options.getPeriod()) { + return true; + } + } + } // Check if we reached maximum number of DISCOVER/SOLICIT sent. if (options.getNumRequests().size() > 0) { if (options.getIpVersion() == 4) { @@ -167,14 +179,14 @@ TestControl::checkExitConditions() const { if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) > 10) && ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) / stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA)) >= - options.getMaxDropPercentage()[0])) { + options.getMaxDropPercentage()[1])) { return(true); } } else if (options.getIpVersion() == 6) { if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) > 10) && ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) / stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR)) >= - options.getMaxDropPercentage()[0])) { + options.getMaxDropPercentage()[1])) { return(true); } } @@ -372,6 +384,18 @@ TestControl::getSentPacketsNum(const ExchangeType xchg_type) const { getSentPacketsNum(static_cast(xchg_type))); } +void +TestControl::initPacketTemplates() { + CommandOptions& options = CommandOptions::instance(); + std::vector template_files = options.getTemplateFiles(); + for (std::vector::const_iterator it = template_files.begin(); + it != template_files.end(); + ++it) { + + std::cout << "Open file " << *it << std::endl; + } +} + void TestControl::initializeStatsMgr() { CommandOptions& options = CommandOptions::instance(); @@ -394,10 +418,11 @@ TestControl::initializeStatsMgr() { } int -TestControl::openSocket(uint16_t port) const { +TestControl::openSocket() const { CommandOptions& options = CommandOptions::instance(); std::string localname = options.getLocalName(); std::string servername = options.getServerName(); + uint16_t port = options.getLocalPort(); uint8_t family = AF_INET; int sock = 0; IOAddress remoteaddr(servername); @@ -522,18 +547,18 @@ TestControl::printStats() const { } void -TestControl::receivePacket4(const TestControlSocket&, +TestControl::receivePacket4(const TestControlSocket& socket, const Pkt4Ptr& pkt4) { - switch(pkt4->getType()) { - case DHCPOFFER : - stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO, pkt4); - break; - case DHCPACK : + if (pkt4->getType() == DHCPOFFER) { + Pkt4Ptr discover_pkt4(stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO, + pkt4)); + CommandOptions::ExchangeMode xchg_mode = + CommandOptions::instance().getExchangeMode(); + if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) { + sendRequest4(socket, pkt4); + } + } else if (pkt4->getType() == DHCPACK) { stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4); - break; - default: - isc_throw(BadValue, "unknown type " << pkt4->getType() - << " of received DHCPv4 packet"); } } @@ -544,14 +569,13 @@ TestControl::receivePacket6(const TestControlSocket& socket, if (packet_type == DHCPV6_ADVERTISE) { Pkt6Ptr solicit_pkt6(stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_SA, pkt6)); - if (solicit_pkt6) { + CommandOptions::ExchangeMode xchg_mode = + CommandOptions::instance().getExchangeMode(); + if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) { sendRequest6(socket, solicit_pkt6, pkt6); } } else if (packet_type == DHCPV6_REPLY) { stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6); - } else { - isc_throw(BadValue, "unknown type " << pkt6->getType() - << " of received DHCPv6 packet"); } } @@ -589,6 +613,9 @@ TestControl::registerOptionFactories4() const { LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_MESSAGE_TYPE, &TestControl::factoryGeneric); + LibDHCP::OptionFactoryRegister(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + &TestControl::factoryGeneric); // DHCP_PARAMETER_REQUEST_LIST option factory. LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST, @@ -613,7 +640,9 @@ TestControl::registerOptionFactories6() const { LibDHCP::OptionFactoryRegister(Option::V6, D6O_CLIENTID, &TestControl::factoryGeneric); - + LibDHCP::OptionFactoryRegister(Option::V6, + D6O_SERVERID, + &TestControl::factoryGeneric); LibDHCP::OptionFactoryRegister(Option::V6, D6O_IA_NA, &TestControl::factoryIana6); @@ -639,10 +668,23 @@ TestControl::registerOptionFactories() const { } } +void +TestControl::reset() { + send_due_ = microsec_clock::universal_time(); + last_sent_ = send_due_; + transid_gen_.reset(); + transid_gen_ = TransidGeneratorPtr(new TransidGenerator()); + first_packet_serverid_.clear(); +} + void TestControl::run() { sent_packets_0_ = 0; sent_packets_1_ = 0; + + // Reset singleton state before test starts. + reset(); + CommandOptions& options = CommandOptions::instance(); // Ip version is not set ONLY in case the command options // were not parsed. This surely means that parse() function @@ -655,7 +697,26 @@ TestControl::run() { registerOptionFactories(); TestControlSocket socket(openSocket()); + // Initialize packet templates. + initPacketTemplates(); + + // Initialize randomization seed. + if (options.isSeeded()) { + srandom(options.getSeed()); + } + + // Preload server with number of packets. + const bool do_preload = true; + for (int i = 0; i < options.getPreload(); ++i) { + if (options.getIpVersion() == 4) { + sendDiscover4(socket, do_preload); + } else if (options.getIpVersion() == 6) { + sendSolicit6(socket, do_preload); + } + } + initializeStatsMgr(); + uint64_t packets_sent = 0; for (;;) { updateSendDue(); @@ -679,7 +740,8 @@ TestControl::run() { } void -TestControl::sendDiscover4(const TestControlSocket& socket) { +TestControl::sendDiscover4(const TestControlSocket& socket, + const bool preload /*= false*/) { ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); // Generate the MAC address to be passed in the packet. @@ -698,6 +760,61 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST)); + // Set client's and server's ports as well as server's address, + // and local (relay) address. + setDefaults4(socket, pkt4); + pkt4->pack(); + IfaceMgr::instance().send(pkt4); + if (!preload) { + if (!stats_mgr4_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " + "hasn't been initialized"); + } + stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, pkt4); + } +} + +void +TestControl::sendRequest4(const TestControlSocket& socket, + const dhcp::Pkt4Ptr& offer_pkt4) { + const uint32_t transid = generateTransid(); + Pkt4Ptr pkt4(new Pkt4(DHCPREQUEST, transid)); + OptionBuffer buf_msg_type; + buf_msg_type.push_back(DHCPREQUEST); + OptionPtr opt_msg_type = Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, + buf_msg_type); + pkt4->addOption(opt_msg_type); + if (first_packet_serverid_.size() > 0) { + pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, + first_packet_serverid_)); + } else { + OptionPtr opt_serverid = + offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER); + if (!opt_serverid) { + isc_throw(BadValue, "there is no SERVER_IDENTIFIER option " + << "in OFFER message"); + } + if (CommandOptions::instance().isUseFirst() && + stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) { + first_packet_serverid_ = opt_serverid->getData(); + } + pkt4->addOption(opt_serverid); + } + + /// Set client address. + asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr(); + if (!yiaddr.getAddress().is_v4()) { + isc_throw(BadValue, "the YIADDR returned in OFFER packet is not " + " IPv4 address"); + } + OptionPtr opt_requested_address = + OptionPtr(new Option(Option::V4, DHO_DHCP_REQUESTED_ADDRESS, + OptionBuffer())); + opt_requested_address->setUint32(yiaddr); + pkt4->addOption(opt_requested_address); + OptionPtr opt_parameter_list = + Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST); + pkt4->addOption(opt_parameter_list); // Set client's and server's ports as well as server's address, // and local (relay) address. setDefaults4(socket, pkt4); @@ -707,14 +824,15 @@ TestControl::sendDiscover4(const TestControlSocket& socket) { isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " "hasn't been initialized"); } - stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, pkt4); + stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA, pkt4); } + void TestControl::sendRequest6(const TestControlSocket& socket, const Pkt6Ptr& solicit_pkt6, const Pkt6Ptr& advertise_pkt6) { - const uint32_t transid = static_cast(random() % 0x00FFFFFF); + const uint32_t transid = generateTransid(); Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid)); // Calculate elapsed time ptime solicit_time = solicit_pkt6->getTimestamp(); @@ -741,11 +859,20 @@ TestControl::sendRequest6(const TestControlSocket& socket, isc_throw(Unexpected, "client id not found in received packet"); } pkt6->addOption(opt_clientid); - OptionPtr opt_serverid = advertise_pkt6->getOption(D6O_SERVERID); - if (!opt_serverid) { - isc_throw(Unexpected, "server id not found in received packet"); + if (first_packet_serverid_.size() > 0) { + pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID, + first_packet_serverid_)); + } else { + OptionPtr opt_serverid = advertise_pkt6->getOption(D6O_SERVERID); + if (!opt_serverid) { + isc_throw(Unexpected, "server id not found in received packet"); + } + if (CommandOptions::instance().isUseFirst() && + stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) { + first_packet_serverid_ = opt_serverid->getData(); + } + pkt6->addOption(opt_serverid); } - pkt6->addOption(opt_serverid); OptionPtr opt_ia_na = advertise_pkt6->getOption(D6O_IA_NA); if (!opt_ia_na) { isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received " @@ -764,7 +891,8 @@ TestControl::sendRequest6(const TestControlSocket& socket, } void -TestControl::sendSolicit6(const TestControlSocket& socket) { +TestControl::sendSolicit6(const TestControlSocket& socket, + const bool preload /*= false*/) { ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); // Generate the MAC address to be passed in the packet. @@ -778,7 +906,9 @@ TestControl::sendSolicit6(const TestControlSocket& socket) { isc_throw(Unexpected, "failed to create SOLICIT packet"); } pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME)); - // pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT)); + if (CommandOptions::instance().isRapidCommit()) { + pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT)); + } pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid)); pkt6->addOption(Option::factory(Option::V6, D6O_ORO)); pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA)); @@ -786,11 +916,13 @@ TestControl::sendSolicit6(const TestControlSocket& socket) { setDefaults6(socket, pkt6); pkt6->pack(); IfaceMgr::instance().send(pkt6); - if (!stats_mgr6_) { - isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " - "hasn't been initialized"); + if (!preload) { + if (!stats_mgr6_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " + "hasn't been initialized"); + } + stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6); } - stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6); } void @@ -811,6 +943,9 @@ TestControl::setDefaults4(const TestControlSocket& socket, pkt->setLocalAddr(IOAddress(socket.getAddress())); // Set relay (GIADDR) address to local address. pkt->setGiaddr(IOAddress(socket.getAddress())); + std::vector mac = generateMacAddress(); + // Set hardware address + pkt->setHWAddr(HTYPE_ETHER, mac.size(), mac); // Pretend that we have one relay (which is us). pkt->setHops(1); } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index a93d05dfc2..6c38e9263b 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -58,6 +58,10 @@ public: typedef boost::shared_ptr StatsMgr6Ptr; // Packet exchange type. typedef StatsMgr<>::ExchangeType ExchangeType; + // Packet template buffer. + typedef std::vector TemplateBuffer; + //Packet template buffers list. + typedef std::list TemplateBufferList; /// \brief Socket wrapper class. /// @@ -333,6 +337,8 @@ protected: /// \return number of exchanges to be started immediatelly. uint64_t getNextExchangesNum() const; + void initPacketTemplates(); + /// \brief Initializes Statistics Manager. /// /// This function initializes Statistics Manager. If there is @@ -350,7 +356,6 @@ protected: /// (for DHCPv6) than broadcast or multicast option is set on /// the socket. /// - /// \param port port to bound socket to. /// \throw isc::BadValue if socket can't be created for given /// interface, local address or remote address. /// \throw isc::InvalidOperation if broadcast option can't be @@ -358,7 +363,7 @@ protected: /// for the v6 socket. /// \throw isc::Unexpected if interal unexpected error occured. /// \return socket descriptor. - int openSocket(uint16_t port = 0) const; + int openSocket() const; /// \brief Print rate statistics. /// @@ -436,6 +441,13 @@ protected: /// depending in whch mode test is currently running. void registerOptionFactories() const; + + /// \brief Resets internal state of the object. + /// + /// Method resets internal state of the object. It has to be + /// called before new test is started. + void reset(); + /// \brief Send DHCPv4 DISCOVER message. /// /// Method creates and sends DHCPv4 DISCOVER message to the server @@ -448,11 +460,25 @@ protected: /// on the number of clients specified from the command line. /// /// \param socket socket to be used to send the message. + /// \param preload preload mode, packets not included in statistics. /// \throw isc::Unexpected if failed to create new packet instance. /// \throw isc::BadValue if MAC address has invalid length. - void sendDiscover4(const TestControlSocket& socket); + void sendDiscover4(const TestControlSocket& socket, + const bool preload = false); - /// \brief Sent DHCPv6 REQUEST message. + /// \brief Send DHCPv4 REQUEST message. + /// + /// Method creates and sends DHCPv4 REQUEST message to the server. + /// + /// \param socket socket to be used to send message. + /// \param offer_pkt4 OFFER packet object. + /// \throw isc::Unexpected if unexpected error occured. + /// \throw isc::InvalidOperation if Statistics Manager has not been + /// initialized. + void sendRequest4(const TestControlSocket& socket, + const dhcp::Pkt4Ptr& offer_pkt4); + + /// \brief Send DHCPv6 REQUEST message. /// /// Method creates and sends DHCPv6 REQUEST message to the server /// with the following options: @@ -485,8 +511,10 @@ protected: /// - D6O_IA_NA. /// /// \param socket socket to be used to send the message. + /// \param preload mode, packets not included in statistics. /// \throw isc::Unexpected if failed to create new packet instance. - void sendSolicit6(const TestControlSocket& socket); + void sendSolicit6(const TestControlSocket& socket, + const bool preload = false); /// \brief Set default DHCPv4 packet parameters. /// @@ -557,9 +585,14 @@ private: StatsMgr4Ptr stats_mgr4_; ///< Statistics Manager 4. StatsMgr6Ptr stats_mgr6_; ///< Statistics Manager 6. - // Pointers to functions. TransidGeneratorPtr transid_gen_; ///< Transaction id generator. + /// Buffer holiding server id received in first packet + dhcp::OptionBuffer first_packet_serverid_; + + /// Packet template buffers. + TemplateBufferList template_buffers_; + uint64_t sent_packets_0_; uint64_t sent_packets_1_; }; diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 52c55b2f10..2284042d58 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -310,7 +310,6 @@ public: void testPkt4Exchange(int iterations_num, int receive_num, int& iterations_performed) const { - uint16_t port = 10547; int sock_handle = 0; NakedTestControl tc; tc.initializeStatsMgr(); @@ -323,25 +322,26 @@ public: generator(new NakedTestControl::IncrementalGenerator()); tc.setTransidGenerator(generator); // Socket is needed to send packets through the interface. - ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + ASSERT_NO_THROW(sock_handle = tc.openSocket()); TestControl::TestControlSocket sock(sock_handle); - int i = 0; - for (; i < iterations_num; ++i) { - if (tc.checkExitConditions()) { - break; - } + uint32_t transid = 0; + for (int i = 0; i < iterations_num; ++i) { ASSERT_NO_THROW(tc.sendDiscover4(sock)); + ++transid; // Do not simulate responses for packets later // that specified as receive_num. This simulates // packet drops. - if (i - 1 < receive_num) { - boost::shared_ptr offer_pkt4(createOfferPkt4(i)); - // Receive OFFER and send REQUEST. + if (i < receive_num) { + boost::shared_ptr offer_pkt4(createOfferPkt4(transid)); ASSERT_NO_THROW(tc.receivePacket4(sock, offer_pkt4)); + ++transid; } + if (tc.checkExitConditions()) { + iterations_performed = i + 1; + break; + } + iterations_performed = i + 1; } - // Return the number of iterations performed. - iterations_performed = i; } /// \brief Test DHCPv6 exchanges. @@ -360,7 +360,6 @@ public: void testPkt6Exchange(int iterations_num, int receive_num, int& iterations_performed) const { - uint16_t port = 10547; int sock_handle = 0; NakedTestControl tc; tc.initializeStatsMgr(); @@ -373,26 +372,28 @@ public: generator(new NakedTestControl::IncrementalGenerator()); tc.setTransidGenerator(generator); // Socket is needed to send packets through the interface. - ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + ASSERT_NO_THROW(sock_handle = tc.openSocket()); TestControl::TestControlSocket sock(sock_handle); - int i = 0; - for (; i < iterations_num; ++i) { - if (tc.checkExitConditions()) { - break; - } + uint32_t transid = 0; + for (int i = 0; i < iterations_num; ++i) { // Do not simulate responses for packets later // that specified as receive_num. This simulates // packet drops. ASSERT_NO_THROW(tc.sendSolicit6(sock)); - if (i - 1 < receive_num) { - boost::shared_ptr advertise_pkt6(createAdvertisePkt6(i)); + ++transid; + if (i < receive_num) { + boost::shared_ptr + advertise_pkt6(createAdvertisePkt6(transid)); // Receive ADVERTISE and send REQUEST. ASSERT_NO_THROW(tc.receivePacket6(sock, advertise_pkt6)); + ++transid; } - + if (tc.checkExitConditions()) { + iterations_performed = i + 1; + break; + } + iterations_performed = i + 1; } - // Return the number of iterations performed. - iterations_performed = i; } /// \brief Test generation of multiple MAC addresses. @@ -463,8 +464,12 @@ private: boost::shared_ptr offer(new Pkt4(DHCPOFFER, transid)); OptionPtr opt_msg_type = Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, OptionBuffer(DHCPOFFER)); + OptionPtr opt_serverid = Option::factory(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + OptionBuffer(4, 1)); offer->setYiaddr(asiolink::IOAddress("127.0.0.1")); offer->addOption(opt_msg_type); + offer->addOption(opt_serverid); offer->updateTimestamp(); return(offer); } @@ -671,13 +676,12 @@ TEST_F(TestControlTest, Packet4) { std::string loopback_iface(getLocalLoopback()); if (!loopback_iface.empty()) { ASSERT_NO_THROW(processCmdLine("perfdhcp -l " + loopback_iface + - " all")); - uint16_t port = 10547; + " -L 10547 all")); NakedTestControl tc; int sock_handle = 0; // We have to create the socket to setup some parameters of // outgoing packet. - ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + ASSERT_NO_THROW(sock_handle = tc.openSocket()); TestControl::TestControlSocket sock(sock_handle); uint32_t transid = 123; boost::shared_ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); @@ -705,13 +709,12 @@ TEST_F(TestControlTest, Packet6) { std::string loopback_iface(getLocalLoopback()); if (!loopback_iface.empty()) { ASSERT_NO_THROW(processCmdLine("perfdhcp -6 -l " + loopback_iface + - " servers")); - uint16_t port = 10547; + " -L 10547 servers")); NakedTestControl tc; int sock_handle = 0; // Create the socket. It will be needed to set packet's // parameters. - ASSERT_NO_THROW(sock_handle = tc.openSocket(port)); + ASSERT_NO_THROW(sock_handle = tc.openSocket()); TestControl::TestControlSocket sock(sock_handle); uint32_t transid = 123; boost::shared_ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); @@ -744,7 +747,7 @@ TEST_F(TestControlTest, Packet4Exchange) { // Set number of iterations to some high value. const int iterations_num = 100; processCmdLine("perfdhcp -l " + loopback_iface - + " -r 100 -n 10 -R 20 127.0.0.1"); + + " -r 100 -n 10 -R 20 -L 10547 127.0.0.1"); // The actual number of iterations will be stored in the // following variable. int iterations_performed = 0; @@ -756,7 +759,7 @@ TEST_F(TestControlTest, Packet4Exchange) { // With the following command line we restrict the maximum // number of dropped packets to 20% of all. processCmdLine("perfdhcp -l " + loopback_iface - + " -r 100 -R 20 -n 20 -D 10% 127.0.0.1"); + + " -r 100 -R 20 -n 20 -D 10% -L 10547 127.0.0.1"); // The number iterations is restricted by the percentage of // dropped packets (-D 10%). We also have to bump up the number // of iterations because the percentage limitation checks starts @@ -781,7 +784,7 @@ TEST_F(TestControlTest, Packet6Exchange) { const int iterations_num = 100; // Set number of iterations to 10. processCmdLine("perfdhcp -l " + loopback_iface - + " -6 -r 100 -n 10 -R 20 ::1"); + + " -6 -r 100 -n 10 -R 20 -L 10547 ::1"); int iterations_performed = 0; // Set number of received packets equal to number of iterations. // This simulates no packet drops. @@ -791,7 +794,7 @@ TEST_F(TestControlTest, Packet6Exchange) { // The maximum number of dropped packets is 3 (because of -D 3). processCmdLine("perfdhcp -l " + loopback_iface - + " -6 -r 100 -n 10 -R 20 -D 3 ::1"); + + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547 ::1"); // For the first 3 packets we are simulating responses from server. // For other packets we don't so packet as 4,5,6 will be dropped and // then test should be interrupted and actual number of iterations will From 23c33b29ab5841a3fe5469d2056708e707938998 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 24 Aug 2012 15:01:04 +0200 Subject: [PATCH 043/148] [1959] Print intermediate statistics (support for -t parameter). --- tests/tools/perfdhcp/stats_mgr.h | 27 +++++++++++++++++++++++++++ tests/tools/perfdhcp/test_control.cc | 20 ++++++++++++++++++++ tests/tools/perfdhcp/test_control.h | 9 +++++++++ 3 files changed, 56 insertions(+) diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index 1e57dda15b..7ea522301c 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -1096,6 +1096,33 @@ public: } } + /// \brief Print intermediate statistics. + /// + /// Method prints intermediate statistics for all exchanges. + /// Statistics includes sent, received and dropped packets + /// counters. + void printIntermediateStats() const { + std::ostringstream stream_sent(""); + std::ostringstream stream_rcvd(""); + std::ostringstream stream_drops(""); + std::string sep(""); + for (ExchangesMapIterator it = exchanges_.begin(); + it != exchanges_.end(); + ++it) { + + if (it != exchanges_.begin()) { + sep = "/"; + } + stream_sent << sep << it->second->getSentPacketsNum(); + stream_rcvd << sep << it->second->getRcvdPacketsNum(); + stream_drops << sep << it->second->getDroppedPacketsNum(); + } + std::cout << "sent: " << stream_sent.str() + << "; received: " << stream_rcvd.str() + << "; drops: " << stream_drops.str() + << std::endl; + } + /// \brief Print timestamps of all packets. /// /// Method prints timestamps of all sent and received diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 42058a9adb..af59105dc6 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -527,6 +527,22 @@ TestControl::printRate() const { } } +void +TestControl::printIntermediateStats() { + CommandOptions& options = CommandOptions::instance(); + int delay = options.getReportDelay(); + ptime now = microsec_clock::universal_time(); + time_period time_since_report(last_report_, now); + if (time_since_report.length().total_seconds() >= delay) { + if (options.getIpVersion() == 4) { + stats_mgr4_->printIntermediateStats(); + } else if (options.getIpVersion() == 6) { + stats_mgr6_->printIntermediateStats(); + } + last_report_ = now; + } +} + void TestControl::printStats() const { printRate(); @@ -672,6 +688,7 @@ void TestControl::reset() { send_due_ = microsec_clock::universal_time(); last_sent_ = send_due_; + last_report_ = send_due_; transid_gen_.reset(); transid_gen_ = TransidGeneratorPtr(new TransidGenerator()); first_packet_serverid_.clear(); @@ -735,6 +752,9 @@ TestControl::run() { } ++packets_sent; } + if (options.getReportDelay() > 0) { + printIntermediateStats(); + } } printStats(); } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 6c38e9263b..c94d7b685e 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -365,6 +365,12 @@ protected: /// \return socket descriptor. int openSocket() const; + /// \brief Print intermediate statistics. + /// + /// Print brief statistics regarding number of sent packets, + /// received packets and dropped packets so far. + void printIntermediateStats(); + /// \brief Print rate statistics. /// /// Method print packet exchange rate statistics. @@ -582,6 +588,9 @@ private: ///< of exchanges. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange /// was initiated. + + boost::posix_time::ptime last_report_; ///< Last intermediate report time. + StatsMgr4Ptr stats_mgr4_; ///< Statistics Manager 4. StatsMgr6Ptr stats_mgr6_; ///< Statistics Manager 6. From b753e8ebd1f6b3e16628e22640efab38fff2cac8 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 24 Aug 2012 16:09:36 +0200 Subject: [PATCH 044/148] [1959] End the program gracefully if interrupted. --- tests/tools/perfdhcp/test_control.cc | 17 ++++++++++++++++- tests/tools/perfdhcp/test_control.h | 10 ++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index af59105dc6..775ed6fd31 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -37,6 +38,8 @@ using namespace isc::asiolink; namespace isc { namespace perfdhcp { +bool TestControl::interrupted_ = false; + TestControl::TestControlSocket::TestControlSocket(int socket) : socket_(socket), addr_("127.0.0.1") { @@ -84,8 +87,11 @@ TestControl::TestControl() { bool TestControl::checkExitConditions() const { + if (interrupted_) { + return(true); + } CommandOptions& options = CommandOptions::instance(); - // Check if test period passed.. + // Check if test period passed. if (options.getPeriod() != 0) { if (options.getIpVersion() == 4) { time_period period(stats_mgr4_->getTestPeriod()); @@ -384,6 +390,11 @@ TestControl::getSentPacketsNum(const ExchangeType xchg_type) const { getSentPacketsNum(static_cast(xchg_type))); } +void +TestControl::handleInterrupt(int) { + interrupted_ = true; +} + void TestControl::initPacketTemplates() { CommandOptions& options = CommandOptions::instance(); @@ -692,6 +703,7 @@ TestControl::reset() { transid_gen_.reset(); transid_gen_ = TransidGeneratorPtr(new TransidGenerator()); first_packet_serverid_.clear(); + interrupted_ = false; } void @@ -722,6 +734,9 @@ TestControl::run() { srandom(options.getSeed()); } + // If user interrupts the program we will exit gracefully. + signal(SIGINT, TestControl::handleInterrupt); + // Preload server with number of packets. const bool do_preload = true; for (int i = 0; i < options.getPreload(); ++i) { diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index c94d7b685e..e3a03afd39 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -584,6 +584,14 @@ private: /// \return number of sent packets. uint64_t getSentPacketsNum(const ExchangeType xchg_type) const; + /// \brief Handle interrupt signal. + /// + /// Function sets flag indicating that program has been + /// interupted. + /// + /// \param sig signal (ignored) + static void handleInterrupt(int sig); + boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk ///< of exchanges. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange @@ -602,6 +610,8 @@ private: /// Packet template buffers. TemplateBufferList template_buffers_; + static bool interrupted_; + uint64_t sent_packets_0_; uint64_t sent_packets_1_; }; From c47f7da793ecc7bb0486d6f78b9405803c2d2701 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 24 Aug 2012 22:29:17 +0200 Subject: [PATCH 045/148] [1959] Implemented diagnostics selectors. --- tests/tools/perfdhcp/command_options.cc | 92 +++++++++ tests/tools/perfdhcp/command_options.h | 3 + tests/tools/perfdhcp/main.cc | 6 +- tests/tools/perfdhcp/stats_mgr.h | 2 +- tests/tools/perfdhcp/test_control.cc | 192 +++++++++++++++--- tests/tools/perfdhcp/test_control.h | 29 ++- .../perfdhcp/tests/stats_mgr_unittest.cc | 4 +- 7 files changed, 290 insertions(+), 38 deletions(-) diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index 14a2e65b9a..fcdb7bd484 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -634,6 +634,98 @@ CommandOptions::nonEmptyString(const std::string& errmsg) const { return sarg; } +void +CommandOptions::printCommandLine() const { + std::cout << "IPv" << static_cast(ipversion_) << std::endl; + if (exchange_mode_ == DO_SA) { + if (ipversion_ == 4) { + std::cout << "DISCOVER-OFFER only" << std::endl; + } else { + std::cout << "SOLICIT-ADVERETISE only" << std::endl; + } + } + if (rate_ != 0) { + std::cout << "rate[1/s]=" << rate_ << std::endl; + } + if (report_delay_ != 0) { + std::cout << "report[s]=" << report_delay_ << std::endl; + } + if (clients_num_ != 0) { + std::cout << "clients=" << clients_num_ << std::endl; + } + for (int i = 0; i < base_.size(); ++i) { + std::cout << "base[" << i << "]=" << base_[i] << std::endl; + } + for (int i = 0; i < num_request_.size(); ++i) { + std::cout << "num-request[" << i << "]=" << num_request_[i] << std::endl; + } + if (period_ != 0) { + std::cout << "test-period=" << period_ << std::endl; + } + for (int i = 0; i < drop_time_.size(); ++i) { + std::cout << "drop-time[" << i << "]=" << drop_time_[i] << std::endl; + } + for (int i = 0; i < max_drop_.size(); ++i) { + std::cout << "max-drop{" << i << "]=" << max_drop_[i] << std::endl; + } + for (int i = 0; i < max_pdrop_.size(); ++i) { + std::cout << "max-pdrop{" << i << "]=" << max_pdrop_[i] << std::endl; + } + if (preload_ != 0) { + std::cout << "preload=" << preload_ << std::endl; + } + std::cout << "aggressivity=" << aggressivity_ << std::endl; + if (getLocalPort() != 0) { + std::cout << "local-port=" << local_port_ << std::endl; + } + if (seeded_) { + std::cout << "seed=" << seed_ << std::endl; + } + if (broadcast_) { + std::cout << "broadcast" << std::endl; + } + if (rapid_commit_) { + std::cout << "rapid-commit" << std::endl; + } + if (use_first_) { + std::cout << "use-first" << std::endl; + } + for (int i = 0; i < template_file_.size(); ++i) { + std::cout << "template-file[" << i << "]=" << template_file_[i] << std::endl; + } + for (int i = 0; i < xid_offset_.size(); ++i) { + std::cout << "xid-offset[" << i << "]=" << xid_offset_[i] << std::endl; + } + if (elp_offset_ != 0) { + std::cout << "elp-offset=" << elp_offset_ << std::endl; + } + for (int i = 0; i < rnd_offset_.size(); ++i) { + std::cout << "rnd-offset[" << i << "]=" << rnd_offset_[i] << std::endl; + } + if (sid_offset_ != 0) { + std::cout << "sid-offset=" << sid_offset_ << std::endl; + } + if (rip_offset_ != 0) { + std::cout << "rip-offset=" << rip_offset_ << std::endl; + } + if (!diags_.empty()) { + std::cout << "diagnostic-selectors=" << diags_ << std::endl; + } + if (!wrapped_.empty()) { + std::cout << "wrapped=" << wrapped_ << std::endl; + } + if (!localname_.empty()) { + if (is_interface_) { + std::cout << "interface=" << localname_ << std::endl; + } else { + std::cout << "local-addr=" << localname_ << std::endl; + } + } + if (!server_name_.empty()) { + std::cout << "server=" << server_name_ << std::endl; + } +} + void CommandOptions::usage() const { fprintf(stdout, "%s", diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h index b75c43864c..b9f2c3a198 100644 --- a/tests/tools/perfdhcp/command_options.h +++ b/tests/tools/perfdhcp/command_options.h @@ -230,6 +230,9 @@ public: /// /// \return server name std::string getServerName() const { return server_name_; } + + /// \brief Prints command line arguments. + void printCommandLine() const; /// \brief Print usage /// diff --git a/tests/tools/perfdhcp/main.cc b/tests/tools/perfdhcp/main.cc index d70b8fae8d..0c706a2b8c 100644 --- a/tests/tools/perfdhcp/main.cc +++ b/tests/tools/perfdhcp/main.cc @@ -38,7 +38,11 @@ main(int argc, char* argv[]) { TestControl& test_control = TestControl::instance(); test_control.run(); } catch (isc::Exception& e) { - std::cout << "Error starting perfdhcp: " << e.what() << std::endl; + std::cout << "Error running perfdhcp: " << e.what() << std::endl; + std::string diags(command_options.getDiags()); + if (diags.find('e') != std::string::npos) { + std::cout << "Fatal error" << std::endl; + } return(1); } return(0); diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index 7ea522301c..806fb8dee6 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -834,7 +834,7 @@ public: /// /// \param counter_key key poitinh to the counter in the counters map. /// \return pointer to specified counter after incrementation. - const CustomCounter& IncrementCounter(const std::string& counter_key) { + const CustomCounter& incrementCounter(const std::string& counter_key) { CustomCounterPtr counter = getCounter(counter_key); return(++(*counter)); } diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 775ed6fd31..c58631f841 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -85,37 +85,55 @@ TestControl::TestControl() { reset(); } +std::string +TestControl::byte2Hex(const uint8_t b) const { + const int b1 = b / 16; + const int b0 = b % 16; + ostringstream stream; + stream << std::hex << b1 << b0 << std::dec; + return stream.str(); +} + bool TestControl::checkExitConditions() const { if (interrupted_) { return(true); } CommandOptions& options = CommandOptions::instance(); + bool test_period_reached = false; // Check if test period passed. if (options.getPeriod() != 0) { if (options.getIpVersion() == 4) { time_period period(stats_mgr4_->getTestPeriod()); if (period.length().total_seconds() >= options.getPeriod()) { - return true; + test_period_reached = true; } } else if (options.getIpVersion() == 6) { time_period period = stats_mgr6_->getTestPeriod(); if (period.length().total_seconds() >= options.getPeriod()) { - return true; + test_period_reached = true; } } } + if (test_period_reached) { + if (testDiags('e')) { + std::cout << "Reached test period." << std::endl; + } + return(true); + } + + bool max_requests = false; // Check if we reached maximum number of DISCOVER/SOLICIT sent. if (options.getNumRequests().size() > 0) { if (options.getIpVersion() == 4) { if (getSentPacketsNum(StatsMgr4::XCHG_DO) >= options.getNumRequests()[0]) { - return(true); + max_requests = true; } } else if (options.getIpVersion() == 6) { if (stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA) >= options.getNumRequests()[0]) { - return(true); + max_requests = true; } } } @@ -124,26 +142,34 @@ TestControl::checkExitConditions() const { if (options.getIpVersion() == 4) { if (stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) >= options.getNumRequests()[1]) { - return(true); + max_requests = true; } } else if (options.getIpVersion() == 6) { if (stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) >= options.getNumRequests()[1]) { - return(true); + max_requests = true; } } } + if (max_requests) { + if (testDiags('e')) { + std::cout << "Reached test period." << std::endl; + } + return(true); + } + // Check if we reached maximum number of drops of OFFER/ADVERTISE packets. + bool max_drops = false; if (options.getMaxDrop().size() > 0) { if (options.getIpVersion() == 4) { if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_DO) >= options.getMaxDrop()[0]) { - return(true); + max_drops = true; } } else if (options.getIpVersion() == 6) { if (stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_SA) >= options.getMaxDrop()[0]) { - return(true); + max_drops = true; } } } @@ -152,30 +178,39 @@ TestControl::checkExitConditions() const { if (options.getIpVersion() == 4) { if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) >= options.getMaxDrop()[1]) { - return(true); + max_drops = true; } } else if (options.getIpVersion() == 6) { if (stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) >= options.getMaxDrop()[1]) { - return(true); + max_drops = true; } } } + if (max_drops) { + if (testDiags('e')) { + std::cout << "Reached maximum drops number." << std::endl; + } + return(true); + } + // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets. + bool max_pdrops = false; if (options.getMaxDropPercentage().size() > 0) { if (options.getIpVersion() == 4) { if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_DO) > 10) && ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_DO) / stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_DO)) >= options.getMaxDropPercentage()[0])) { - return(true); + max_pdrops = true; + } } else if (options.getIpVersion() == 6) { if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA) > 10) && ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_SA) / stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_SA)) >= options.getMaxDropPercentage()[0])) { - return(true); + max_pdrops = true; } } } @@ -186,17 +221,24 @@ TestControl::checkExitConditions() const { ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) / stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA)) >= options.getMaxDropPercentage()[1])) { - return(true); + max_pdrops = true; } } else if (options.getIpVersion() == 6) { if ((stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR) > 10) && ((100. * stats_mgr6_->getDroppedPacketsNum(StatsMgr6::XCHG_RR) / stats_mgr6_->getSentPacketsNum(StatsMgr6::XCHG_RR)) >= options.getMaxDropPercentage()[1])) { - return(true); + max_pdrops = true; } } } + if (max_pdrops) { + if (testDiags('e')) { + std::cout << "Reached maximum percentage of drops." << std::endl; + } + return(true); + } + return(false); } @@ -335,9 +377,6 @@ TestControl::getNextExchangesNum() const { uint64_t due_exchanges = 0; // Get current time. ptime now(microsec_clock::universal_time()); - // The due time indicates when we should start sending next chunk - // of packets. If it is already due time, we should calculate - // how many packets to send. if (now >= send_due_) { // If rate is specified from the command line we have to // synchornize with it. @@ -426,6 +465,19 @@ TestControl::initializeStatsMgr() { stats_mgr6_->addExchangeStats(StatsMgr6::XCHG_RR); } } + if (testDiags('i')) { + if (options.getIpVersion() == 4) { + stats_mgr4_->addCustomCounter("latesend", "Late sent packets"); + stats_mgr4_->addCustomCounter("shortwait", "Short waits for packets"); + stats_mgr4_->addCustomCounter("multircvd", "Multiple packets receives"); + // stats_mgr4_->addCustomCounter("latercvd", "Late received packets"); + } else if (options.getIpVersion() == 6) { + stats_mgr6_->addCustomCounter("latesend", "Late sent packets"); + stats_mgr6_->addCustomCounter("shortwait", "Short waits for packets"); + stats_mgr6_->addCustomCounter("multircvd", "Multiple packets receives"); + // stats_mgr6_->addCustomCounter("latercvd", "Late received packets"); + } + } } int @@ -516,6 +568,23 @@ TestControl::openSocket() const { return(sock); } +void +TestControl::printDiagnostics() const { + CommandOptions& options = CommandOptions::instance(); + if (testDiags('a')) { + // Print all command line parameters. + options.printCommandLine(); + + // Print MAC and DUID. + std::cout << "Set MAC to " << vector2Hex(options.getMacPrefix(), "::") + << std::endl; + if (options.getDuidPrefix().size() > 0) { + std::cout << "Set DUID to " << vector2Hex(options.getDuidPrefix()) << std::endl; + } + + } +} + void TestControl::printRate() const { double rate = 0; @@ -564,15 +633,37 @@ TestControl::printStats() const { "hasn't been initialized"); } stats_mgr4_->printStats(); + if (testDiags('i')) { + stats_mgr4_->printCustomCounters(); + } } else if (options.getIpVersion() == 6) { if (!stats_mgr6_) { isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " "hasn't been initialized"); } stats_mgr6_->printStats(); + if (testDiags('i')) { + stats_mgr6_->printCustomCounters(); + } } } +std::string +TestControl::vector2Hex(const std::vector& vec, + const std::string& separator /* ="" */) const { + std::ostringstream stream; + for (std::vector::const_iterator it = vec.begin(); + it != vec.end(); + ++it) { + if (it == vec.begin()) { + stream << byte2Hex(*it); + } else { + stream << separator << byte2Hex(*it); + } + } + return(stream.str()); +} + void TestControl::receivePacket4(const TestControlSocket& socket, const Pkt4Ptr& pkt4) { @@ -610,12 +701,17 @@ void TestControl::receivePackets(const TestControlSocket& socket) { int timeout = 0; bool receiving = true; + uint64_t received = 0; while (receiving) { if (CommandOptions::instance().getIpVersion() == 4) { Pkt4Ptr pkt4 = IfaceMgr::instance().receive4(timeout); if (!pkt4) { receiving = false; } else { + ++received; + if ((received > 1) && testDiags('i')) { + stats_mgr4_->incrementCounter("multircvd"); + } pkt4->unpack(); receivePacket4(socket, pkt4); } @@ -624,6 +720,10 @@ TestControl::receivePackets(const TestControlSocket& socket) { if (!pkt6) { receiving = false; } else { + ++received; + if ((received > 1) && testDiags('i')) { + stats_mgr6_->incrementCounter("multircvd"); + } if (pkt6->unpack()) { receivePacket6(socket, pkt6); } @@ -708,9 +808,6 @@ TestControl::reset() { void TestControl::run() { - sent_packets_0_ = 0; - sent_packets_1_ = 0; - // Reset singleton state before test starts. reset(); @@ -723,6 +820,9 @@ TestControl::run() { isc_throw(InvalidOperation, "command options must be parsed before running a test"); } + + printDiagnostics(); + registerOptionFactories(); TestControlSocket socket(openSocket()); @@ -749,14 +849,22 @@ TestControl::run() { initializeStatsMgr(); - uint64_t packets_sent = 0; for (;;) { updateSendDue(); if (checkExitConditions()) { break; } uint64_t packets_due = getNextExchangesNum(); + if ((packets_due == 0) && testDiags('i')) { + if (options.getIpVersion() == 4) { + stats_mgr4_->incrementCounter("shortwait"); + } else if (options.getIpVersion() == 6) { + stats_mgr6_->incrementCounter("shortwait"); + } + } + // @todo: set non-zero timeout for packets once we implement + // microseconds timeout in IfaceMgr. receivePackets(socket); for (uint64_t i = packets_due; i > 0; --i) { @@ -765,19 +873,24 @@ TestControl::run() { } else { sendSolicit6(socket); } - ++packets_sent; } if (options.getReportDelay() > 0) { printIntermediateStats(); } } printStats(); + if (testDiags('s') && (first_packet_serverid_.size() > 0)) { + std::cout << "Server id: " << vector2Hex(first_packet_serverid_) << std::endl; + } + // Diagnostics flag 'e' means show exit reason. + if (testDiags('e')) { + std::cout << "Interrupted" << std::endl; + } } void TestControl::sendDiscover4(const TestControlSocket& socket, const bool preload /*= false*/) { - ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); // Generate the MAC address to be passed in the packet. std::vector mac_address = generateMacAddress(); @@ -819,7 +932,8 @@ TestControl::sendRequest4(const TestControlSocket& socket, OptionPtr opt_msg_type = Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE, buf_msg_type); pkt4->addOption(opt_msg_type); - if (first_packet_serverid_.size() > 0) { + if (CommandOptions::instance().isUseFirst() && + (first_packet_serverid_.size() > 0)) { pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, first_packet_serverid_)); } else { @@ -829,8 +943,7 @@ TestControl::sendRequest4(const TestControlSocket& socket, isc_throw(BadValue, "there is no SERVER_IDENTIFIER option " << "in OFFER message"); } - if (CommandOptions::instance().isUseFirst() && - stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) { + if (stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) { first_packet_serverid_ = opt_serverid->getData(); } pkt4->addOption(opt_serverid); @@ -894,7 +1007,8 @@ TestControl::sendRequest6(const TestControlSocket& socket, isc_throw(Unexpected, "client id not found in received packet"); } pkt6->addOption(opt_clientid); - if (first_packet_serverid_.size() > 0) { + if (CommandOptions::instance().isUseFirst() && + (first_packet_serverid_.size() > 0)) { pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID, first_packet_serverid_)); } else { @@ -902,8 +1016,7 @@ TestControl::sendRequest6(const TestControlSocket& socket, if (!opt_serverid) { isc_throw(Unexpected, "server id not found in received packet"); } - if (CommandOptions::instance().isUseFirst() && - stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) { + if (stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) { first_packet_serverid_ = opt_serverid->getData(); } pkt6->addOption(opt_serverid); @@ -928,7 +1041,6 @@ TestControl::sendRequest6(const TestControlSocket& socket, void TestControl::sendSolicit6(const TestControlSocket& socket, const bool preload /*= false*/) { - ++sent_packets_0_; last_sent_ = microsec_clock::universal_time(); // Generate the MAC address to be passed in the packet. std::vector mac_address = generateMacAddress(); @@ -1003,6 +1115,15 @@ TestControl::setDefaults6(const TestControlSocket& socket, pkt->setRemoteAddr(IOAddress(options.getServerName())); } +bool +TestControl::testDiags(const char diag) const { + std::string diags(CommandOptions::instance().getDiags()); + if (diags.find(diag) != std::string::npos) { + return true; + } + return false; +} + void TestControl::updateSendDue() { // If default constructor was called, this should not happen but @@ -1026,6 +1147,17 @@ TestControl::updateSendDue() { } // Calculate due time to initate next chunk of exchanges. send_due_ = last_sent_ + time_duration(0, 0, 0, duration); + // Check if it is already due. + ptime now(microsec_clock::universal_time()); + if (now > send_due_) { + if (testDiags('i')) { + if (options.getIpVersion() == 4) { + stats_mgr4_->incrementCounter("latesend"); + } else if (options.getIpVersion() == 6) { + stats_mgr6_->incrementCounter("latesend"); + } + } + } } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index e3a03afd39..9b634ce5d7 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -552,6 +552,12 @@ protected: void setDefaults6(const TestControlSocket& socket, const dhcp::Pkt6Ptr& pkt); + /// \brief Find of diagnostic flag has been set. + /// + /// \param diag diagnostic flag (a,e,i,s,r,t,T). + /// \return true if diagnostics flag has been set. + bool testDiags(const char diag) const; + /// \brief Update due time to initiate next chunk of exchanges. /// /// Method updates due time to initiate next chunk of exchanges. @@ -561,6 +567,12 @@ protected: private: + /// \brief Convert binary value to hex string. + /// + /// \param b byte to convert. + /// \return hex string. + std::string byte2Hex(const uint8_t b) const; + /// \brief Generate transaction id using random function. /// /// \return generated transaction id value. @@ -592,6 +604,18 @@ private: /// \param sig signal (ignored) static void handleInterrupt(int sig); + /// \brief Convert vector in hexadecimal string. + /// + /// \param vec vector to be converted. + /// \param separator separator. + std::string vector2Hex(const std::vector& vec, + const std::string& separator = "") const; + + /// \brief Print main diagnostics data. + /// + /// Method prints main diagnostics data. + void printDiagnostics() const; + boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk ///< of exchanges. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange @@ -610,10 +634,7 @@ private: /// Packet template buffers. TemplateBufferList template_buffers_; - static bool interrupted_; - - uint64_t sent_packets_0_; - uint64_t sent_packets_1_; + static bool interrupted_; ///< Is program interrupted. }; } // namespace perfdhcp diff --git a/tests/tools/perfdhcp/tests/stats_mgr_unittest.cc b/tests/tools/perfdhcp/tests/stats_mgr_unittest.cc index 2233847bb1..d6b3aeff24 100644 --- a/tests/tools/perfdhcp/tests/stats_mgr_unittest.cc +++ b/tests/tools/perfdhcp/tests/stats_mgr_unittest.cc @@ -387,13 +387,13 @@ TEST_F(StatsMgrTest, CustomCounters) { // Increment one of the counters 10 times. const uint64_t tooshort_num = 10; for (uint64_t i = 0; i < tooshort_num; ++i) { - stats_mgr->IncrementCounter(too_short_key); + stats_mgr->incrementCounter(too_short_key); } // Increment another counter by 5 times. const uint64_t toolate_num = 5; for (uint64_t i = 0; i < toolate_num; ++i) { - stats_mgr->IncrementCounter(too_late_key); + stats_mgr->incrementCounter(too_late_key); } // Check counter's current value and name. From fcde1f32cd4925a3c5b4c061a8b79fb83e2406af Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 28 Aug 2012 12:54:05 +0200 Subject: [PATCH 046/148] [2180] Make the SQLITE_SETUP message a warning Since creating new file is suspicious, the administrator may have misspelled some file name. The message explains the problem and shows the file name as well. Also, removed a duplicate message, created a new instance for it. --- src/lib/datasrc/datasrc_messages.mes | 14 ++++++++++++-- src/lib/datasrc/sqlite3_accessor.cc | 10 +++++----- src/lib/datasrc/sqlite3_datasrc.cc | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes index 6837476243..c78dab6e81 100644 --- a/src/lib/datasrc/datasrc_messages.mes +++ b/src/lib/datasrc/datasrc_messages.mes @@ -787,10 +787,20 @@ example.com). However, this name is not contained in any zone in the data source. This is an error since it indicates a problem in the earlier processing of the query. -% DATASRC_SQLITE_SETUP setting up SQLite database +% DATASRC_SQLITE_SETUP setting up new SQLite3 database in '%1' The database for SQLite data source was found empty. It is assumed this is the first run and it is being initialized with current schema. It'll still contain -no data, but it will be ready for use. +no data, but it will be ready for use. If this is indeed the first run of +Bind10, it is to be expected and completely harmless. If you just configured +a data source to point to an existing file and you see this, you may have +misspelled the file name. + +% DATASRC_SQLITE_SETUP_OLD_API setting up new SQLite database +The database for SQLite data source was found empty. It is assumed this is the +first run and it is being initialized with current schema. It'll still contain +no data, but it will be ready for use. This is similar to DATASRC_SQLITE_SETUP +message, but it is logged from the old API. You should never see it, since the +API is deprecated. % DATASRC_STATIC_CLASS_NOT_CH static data source can handle CH class only An error message indicating that a query requesting a RR for a class other diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc index ba21de8912..457d578c4b 100644 --- a/src/lib/datasrc/sqlite3_accessor.cc +++ b/src/lib/datasrc/sqlite3_accessor.cc @@ -474,8 +474,8 @@ private: // return db version pair -createDatabase(sqlite3* db) { - logger.info(DATASRC_SQLITE_SETUP); +createDatabase(sqlite3* db, const std::string& name) { + logger.warn(DATASRC_SQLITE_SETUP).arg(name); // try to get an exclusive lock. Once that is obtained, do the version // check *again*, just in case this process was racing another @@ -501,12 +501,12 @@ createDatabase(sqlite3* db) { } void -checkAndSetupSchema(Initializer* initializer) { +checkAndSetupSchema(Initializer* initializer, const std::string& name) { sqlite3* const db = initializer->params_.db_; pair schema_version = checkSchemaVersion(db); if (schema_version.first == -1) { - schema_version = createDatabase(db); + schema_version = createDatabase(db, name); } else if (schema_version.first != SQLITE_SCHEMA_MAJOR_VERSION) { LOG_ERROR(logger, DATASRC_SQLITE_INCOMPATIBLE_VERSION) .arg(schema_version.first).arg(schema_version.second) @@ -540,7 +540,7 @@ SQLite3Accessor::open(const std::string& name) { isc_throw(SQLite3Error, "Cannot open SQLite database file: " << name); } - checkAndSetupSchema(&initializer); + checkAndSetupSchema(&initializer, name); initializer.move(dbparameters_.get()); } diff --git a/src/lib/datasrc/sqlite3_datasrc.cc b/src/lib/datasrc/sqlite3_datasrc.cc index b450cd5b56..bced1ae5b1 100644 --- a/src/lib/datasrc/sqlite3_datasrc.cc +++ b/src/lib/datasrc/sqlite3_datasrc.cc @@ -788,7 +788,7 @@ private: // return db version pair create_database(sqlite3* db) { - logger.info(DATASRC_SQLITE_SETUP); + logger.info(DATASRC_SQLITE_SETUP_OLD_API); // try to get an exclusive lock. Once that is obtained, do the version // check *again*, just in case this process was racing another From 627a1bbee79944d24a1aaecf3ba4c87d47b1003b Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 28 Aug 2012 13:51:17 +0200 Subject: [PATCH 047/148] [2188] Test loading with comments in strings Obviously, it fails. --- src/bin/loadzone/tests/correct/correct_test.sh.in | 4 ++++ src/bin/loadzone/tests/correct/get_zonedatas.py | 2 +- src/bin/loadzone/tests/correct/known.test.out | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/bin/loadzone/tests/correct/correct_test.sh.in b/src/bin/loadzone/tests/correct/correct_test.sh.in index d944451034..e3f6a8414a 100755 --- a/src/bin/loadzone/tests/correct/correct_test.sh.in +++ b/src/bin/loadzone/tests/correct/correct_test.sh.in @@ -48,6 +48,9 @@ ${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 ttlext.db >> / echo "loadzone example.com. from example.db" ${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 example.db >> /dev/null +echo "loadzone comment.example.com. from comment.db" +${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 comment.db >> /dev/null + echo "I:test master file \$INCLUDE semantics" echo "I:test master file BIND 8 compatibility TTL and \$TTL semantics" echo "I:test master file RFC1035 TTL and \$TTL semantics" @@ -55,6 +58,7 @@ echo "I:test master file BIND8 compatibility and mixed \$INCLUDE with \$TTL sema echo "I:test master file RFC1035 TTL and mixed \$INCLUDE with \$TTL semantics" echo "I:test master file BIND9 extenstion of TTL" echo "I:test master file RFC1035 missing CLASS, TTL, NAME semantics" +echo "I:test master file comments" ${PYTHON_EXEC} ${TEST_FILE_PATH}/get_zonedatas.py ${TEST_OUTPUT_PATH}/zone.sqlite3 > ${TEST_OUTPUT_PATH}/test.out echo "Compare test results." diff --git a/src/bin/loadzone/tests/correct/get_zonedatas.py b/src/bin/loadzone/tests/correct/get_zonedatas.py index faa563449c..5bef90d9fe 100644 --- a/src/bin/loadzone/tests/correct/get_zonedatas.py +++ b/src/bin/loadzone/tests/correct/get_zonedatas.py @@ -1,7 +1,7 @@ from isc.datasrc import sqlite3_ds import sys ZONE_FILE = sys.argv[1] -zonename_set = ["include.", "ttl1.", "ttl2.", "mix1.", "mix2.", "ttlext.", "example.com."] +zonename_set = ["include.", "ttl1.", "ttl2.", "mix1.", "mix2.", "ttlext.", "example.com.", "comment.example.com."] for zone_name in zonename_set: for rr_data in sqlite3_ds.get_zone_datas(zone_name, ZONE_FILE): data_len = len(rr_data[2]) diff --git a/src/bin/loadzone/tests/correct/known.test.out b/src/bin/loadzone/tests/correct/known.test.out index 8e2fe3cf3c..eec692e976 100644 --- a/src/bin/loadzone/tests/correct/known.test.out +++ b/src/bin/loadzone/tests/correct/known.test.out @@ -77,3 +77,9 @@ ns2.example.com. 80 IN A 1.1.1.1 ns3.example.com. 60 IN A 2.2.2.2 ns4.example.com. 60 IN A 3.3.3.3 ns5.example.com. 90 IN A 4.4.4.4 +comment.example.com. 60 IN SOA ns1.example.com. hostmaster.example.com. 1 43200 900 1814400 7200 +comment.example.com. 60 IN NS ns1.example.com. +comment.example.com. 60 IN TXT "Simple text" +comment.example.com. 60 IN TXT "; No comment" +comment.example.com. 60 IN TXT "Also no comment here" +comment.example.com. 60 IN TXT "A combination ; see?" From 5e8d62ed54882e12dfa5159818b2a84239510987 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 28 Aug 2012 14:28:44 +0200 Subject: [PATCH 048/148] [2188] Don't strip comments in the middle of string --- src/lib/python/isc/datasrc/master.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib/python/isc/datasrc/master.py b/src/lib/python/isc/datasrc/master.py index bba080544d..2c22190899 100644 --- a/src/lib/python/isc/datasrc/master.py +++ b/src/lib/python/isc/datasrc/master.py @@ -46,11 +46,16 @@ def pop(line): # whitespace removed, and all other whitespace compressed to # single spaces ######################################################################### -decomment = re.compile('\s*(?:;.*)+') +decomment = re.compile('^\s*((?:[^;"]|"[^"]*")*)\s*(?:|;.*)$') +# Regular expression explained: +# First, ignore any whitespace at the start. Then take the content, +# each bit is either a harmless character (no ; nor ") or a string - +# sequence between " " not containing double quotes. Then there may +# be a comment at the end. def cleanup(s): global decomment s = s.strip().expandtabs() - s = decomment.sub('', s) + s = decomment.search(s).group(1) return ' '.join(s.split()) ######################################################################### From 519704852db4162fd51ba5ea448ed96e67c025fd Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 28 Aug 2012 14:54:34 +0200 Subject: [PATCH 049/148] [2188] Add missing file I forgot to add it before. --- src/bin/loadzone/tests/correct/Makefile.am | 1 + src/bin/loadzone/tests/correct/comment.db | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 src/bin/loadzone/tests/correct/comment.db diff --git a/src/bin/loadzone/tests/correct/Makefile.am b/src/bin/loadzone/tests/correct/Makefile.am index fb882bae4b..a3c67d4a9c 100644 --- a/src/bin/loadzone/tests/correct/Makefile.am +++ b/src/bin/loadzone/tests/correct/Makefile.am @@ -12,6 +12,7 @@ EXTRA_DIST += ttl1.db EXTRA_DIST += ttl2.db EXTRA_DIST += ttlext.db EXTRA_DIST += example.db +EXTRA_DIST += comment.db noinst_SCRIPTS = correct_test.sh diff --git a/src/bin/loadzone/tests/correct/comment.db b/src/bin/loadzone/tests/correct/comment.db new file mode 100644 index 0000000000..79ce9b76a8 --- /dev/null +++ b/src/bin/loadzone/tests/correct/comment.db @@ -0,0 +1,8 @@ +; Test removal of comments and not removal from strings. +; We had a bug - see #2188. +comment.example.com. 60 IN SOA ns1.example.com. hostmaster.example.com. 1 43200 900 1814400 7200 +comment.example.com. 60 IN NS ns1.example.com. +comment.example.com. 60 IN TXT "Simple text" +comment.example.com. 60 IN TXT "; No comment" +comment.example.com. 60 IN TXT "Also no comment here" ; But here it is a comment +comment.example.com. 60 IN TXT "A combination ; see?" ; This is a "comment From abbc63a651ff0329613d46901f4cb186078e9524 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Tue, 28 Aug 2012 16:14:13 +0200 Subject: [PATCH 050/148] [357] timeout on idle TCP connections in TCPServer for now with a fixed size --- src/lib/asiodns/tcp_server.cc | 23 +++++++++++++ src/lib/asiodns/tcp_server.h | 8 ++++- src/lib/asiodns/tests/dns_server_unittest.cc | 34 ++++++++++++++++++-- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc index 8e4b4d6f05..3f9e2412d2 100644 --- a/src/lib/asiodns/tcp_server.cc +++ b/src/lib/asiodns/tcp_server.cc @@ -72,6 +72,21 @@ TCPServer::TCPServer(io_service& io_service, int fd, int af, } } +namespace { + // Called by the timeout_ deadline timer if the client takes too long. + // If not aborted, cancels the given socket + // (in which case TCPServer::operator() will be called to continue, + // with an 'aborted' error code + void do_timeout(asio::ip::tcp::socket& socket, + const asio::error_code& error) + { + if (error != asio::error::operation_aborted) { + socket.cancel(); + } else { + } + } +} + void TCPServer::operator()(asio::error_code ec, size_t length) { /// Because the coroutine reentry block is implemented as @@ -114,6 +129,11 @@ TCPServer::operator()(asio::error_code ec, size_t length) { /// asynchronous read call. data_.reset(new char[MAX_LENGTH]); + timeout_.reset(new asio::deadline_timer(io_)); + timeout_->expires_from_now(boost::posix_time::milliseconds(1000)); + timeout_->async_wait(boost::bind(&do_timeout, boost::ref(*socket_), + asio::placeholders::error)); + /// Read the message, in two parts. First, the message length: CORO_YIELD async_read(*socket_, asio::buffer(data_.get(), TCP_MESSAGE_LENGTHSIZE), *this); @@ -209,6 +229,9 @@ TCPServer::operator()(asio::error_code ec, size_t length) { // will simply exit at that time). CORO_YIELD async_write(*socket_, bufs, *this); + // All done, cancel the timeout timer + timeout_->cancel(); + // TODO: should we keep the connection open for a short time // to see if new requests come in? socket_->close(); diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h index 01695e4093..1d95a30b2c 100644 --- a/src/lib/asiodns/tcp_server.h +++ b/src/lib/asiodns/tcp_server.h @@ -34,7 +34,7 @@ namespace asiodns { /// \brief A TCP-specific \c DNSServer object. /// /// This class inherits from both \c DNSServer and from \c coroutine, -/// defined in coroutine.h. +/// defined in coroutine.h. class TCPServer : public virtual DNSServer, public virtual coroutine { public: /// \brief Constructor @@ -122,6 +122,12 @@ private: boost::shared_ptr peer_; boost::shared_ptr iosock_; + + // Timer used to timeout on tcp connections + // This is a shared pointer because we need to have something + // that outlives the operator() call and is copyable (for CORO_FORK) + // even though it is only set after fork + boost::shared_ptr timeout_; }; } // namespace asiodns diff --git a/src/lib/asiodns/tests/dns_server_unittest.cc b/src/lib/asiodns/tests/dns_server_unittest.cc index a5e83c7757..e728d4eb77 100644 --- a/src/lib/asiodns/tests/dns_server_unittest.cc +++ b/src/lib/asiodns/tests/dns_server_unittest.cc @@ -258,7 +258,8 @@ class TCPClient : public SimpleClient { // this includes connect, send message and recevice message static const unsigned int SERVER_TIME_OUT = 2; TCPClient(asio::io_service& service, const ip::tcp::endpoint& server) - : SimpleClient(service, SERVER_TIME_OUT) + : SimpleClient(service, SERVER_TIME_OUT), + send_data_(true), send_data_len_(true) { server_ = server; socket_.reset(new ip::tcp::socket(service)); @@ -280,13 +281,23 @@ class TCPClient : public SimpleClient { std::string(received_data_ + 2)); } + // if set to false, does not actually send data length + void setSendDataLen(bool send_data_len) { + send_data_len_ = send_data_len; + } + + // if set to false, does not actually send data + void setSendData(bool send_data) { + send_data_ = send_data; + } + private: void stopWaitingforResponse() { socket_->close(); } void connectHandler(const asio::error_code& error) { - if (!error) { + if (!error && send_data_len_) { data_to_send_len_ = htons(data_to_send_len_); socket_->async_send(buffer(&data_to_send_len_, 2), boost::bind(&TCPClient::sendMessageBodyHandler, @@ -297,7 +308,7 @@ class TCPClient : public SimpleClient { void sendMessageBodyHandler(const asio::error_code& error, size_t send_bytes) { - if (!error && send_bytes == 2) { + if (!error && send_bytes == 2 && send_data_) { socket_->async_send(buffer(data_to_send_.c_str(), data_to_send_.size() + 1), boost::bind(&TCPClient::finishSendHandler, this, _1, _2)); @@ -316,6 +327,8 @@ class TCPClient : public SimpleClient { ip::tcp::endpoint server_; std::string data_to_send_; uint16_t data_to_send_len_; + bool send_data_; + bool send_data_len_; }; // \brief provide the context which including two clients and @@ -565,6 +578,21 @@ TYPED_TEST(DNSServerTest, stopTCPServerAfterOneQuery) { EXPECT_TRUE(this->serverStopSucceed()); } +TYPED_TEST(DNSServerTest, TCPTimeoutOnLen) { + this->tcp_client_->setSendDataLen(false); + this->testStopServerByStopper(this->tcp_server_, this->tcp_client_, + this->tcp_client_); + EXPECT_EQ("", this->tcp_client_->getReceivedData()); + EXPECT_FALSE(this->serverStopSucceed()); +} + +TYPED_TEST(DNSServerTest, TCPTimeout) { + this->tcp_client_->setSendData(false); + this->testStopServerByStopper(this->tcp_server_, this->tcp_client_, + this->tcp_client_); + EXPECT_EQ("", this->tcp_client_->getReceivedData()); + EXPECT_FALSE(this->serverStopSucceed()); +} // Test whether tcp server stopped successfully before server start to serve TYPED_TEST(DNSServerTest, stopTCPServerBeforeItStartServing) { From 2cefc6958e480f3143117962407d48636af18944 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Wed, 29 Aug 2012 17:25:59 +0200 Subject: [PATCH 051/148] [357] configuration for tcp_recv_timeout in auth --- src/bin/auth/auth.spec.pre.in | 5 +++ src/bin/auth/auth_config.cc | 20 +++++++++ src/bin/auth/auth_srv.cc | 5 +++ src/bin/auth/auth_srv.h | 3 ++ src/bin/auth/tests/config_syntax_unittest.cc | 26 ++++++++++-- src/bin/auth/tests/config_unittest.cc | 9 ++++ src/lib/asiodns/dns_server.h | 4 +- src/lib/asiodns/dns_service.cc | 17 ++++++++ src/lib/asiodns/dns_service.h | 4 ++ src/lib/asiodns/tcp_server.cc | 9 +++- src/lib/asiodns/tcp_server.h | 15 +++++++ src/lib/asiodns/tests/dns_server_unittest.cc | 44 +++++++++++++------- src/lib/testutils/mockups.h | 9 ++++ 13 files changed, 149 insertions(+), 21 deletions(-) diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in index b9587e6127..3c31c2d86e 100644 --- a/src/bin/auth/auth.spec.pre.in +++ b/src/bin/auth/auth.spec.pre.in @@ -90,6 +90,11 @@ } ] } + }, + { "item_name": "tcp_recv_timeout", + "item_type": "integer", + "item_optional": false, + "item_default": 1000 } ], "commands": [ diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc index a67632f9cb..987f1ee53e 100644 --- a/src/bin/auth/auth_config.cc +++ b/src/bin/auth/auth_config.cc @@ -116,6 +116,24 @@ private: */ AddrListPtr rollbackAddresses_; }; + +class TCPRecvTimeoutConfig : public AuthConfigParser { +public: + TCPRecvTimeoutConfig(AuthSrv& server) : server_(server) + {} + + virtual void build(ConstElementPtr config) { + timeout_ = config->intValue(); + } + + virtual void commit() { + server_.setTCPRecvTimeout(timeout_); + } +private: + AuthSrv& server_; + size_t timeout_; +}; + } // end of unnamed namespace AuthConfigParser* @@ -147,6 +165,8 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) { // We need to return something. The VersionConfig is empty now, // so we may abuse that one, as it is a short-term solution only. return (new VersionConfig()); + } else if (config_id == "tcp_recv_timeout") { + return (new TCPRecvTimeoutConfig(server)); } else { isc_throw(AuthConfigError, "Unknown configuration identifier: " << config_id); diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc index 6e5666f43f..9dbcf4772b 100644 --- a/src/bin/auth/auth_srv.cc +++ b/src/bin/auth/auth_srv.cc @@ -927,3 +927,8 @@ AuthSrv::getClientListClasses() const { } return (result); } + +void +AuthSrv::setTCPRecvTimeout(size_t timeout) { + dnss_->setTCPRecvTimeout(timeout); +} diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h index 2c2b41566d..e2d7d2f47b 100644 --- a/src/bin/auth/auth_srv.h +++ b/src/bin/auth/auth_srv.h @@ -319,6 +319,9 @@ public: /// has been set by setClientList. std::vector getClientListClasses() const; + /// \brief Sets the timeout for incoming TCP connections + void setTCPRecvTimeout(size_t timeout); + private: AuthSrvImpl* impl_; isc::asiolink::SimpleCallback* checkin_; diff --git a/src/bin/auth/tests/config_syntax_unittest.cc b/src/bin/auth/tests/config_syntax_unittest.cc index 8caedfdd3f..a7d9bbce66 100644 --- a/src/bin/auth/tests/config_syntax_unittest.cc +++ b/src/bin/auth/tests/config_syntax_unittest.cc @@ -36,7 +36,8 @@ TEST_F(AuthConfigSyntaxTest, inmemoryDefaultFileType) { EXPECT_TRUE( mspec_.validateConfig( Element::fromJSON( - "{\"listen_on\": [], \"datasources\": " + "{\"tcp_recv_timeout\": 1000," + " \"listen_on\": [], \"datasources\": " " [{\"type\": \"memory\", \"class\": \"IN\", " " \"zones\": [{\"origin\": \"example.com\"," " \"file\": \"" @@ -48,7 +49,8 @@ TEST_F(AuthConfigSyntaxTest, inmemorySQLite3Backend) { EXPECT_TRUE( mspec_.validateConfig( Element::fromJSON( - "{\"datasources\": " + "{\"tcp_recv_timeout\": 1000," + " \"datasources\": " " [{\"type\": \"memory\"," " \"zones\": [{\"origin\": \"example.com\"," " \"file\": \"" @@ -58,14 +60,30 @@ TEST_F(AuthConfigSyntaxTest, inmemorySQLite3Backend) { TEST_F(AuthConfigSyntaxTest, badInmemoryFileType) { // filetype must be a string - EXPECT_FALSE( + ASSERT_FALSE( mspec_.validateConfig( Element::fromJSON( - "{\"datasources\": " + "{\"tcp_recv_timeout\": 1000," + " \"datasources\": " " [{\"type\": \"memory\"," " \"zones\": [{\"origin\": \"example.com\"," " \"file\": \"" TEST_DATA_DIR "/example.zone\"," " \"filetype\": 42}]}]}"), false)); } + +TEST_F(AuthConfigSyntaxTest, badTCPRecvTimeout) { + // tcp_recv_timeout must be int + EXPECT_FALSE( + mspec_.validateConfig( + Element::fromJSON( + "{\"tcp_recv_timeout\": \"foo\"," + " \"datasources\": " + " [{\"type\": \"memory\"," + " \"zones\": [{\"origin\": \"example.com\"," + " \"file\": \"" + TEST_DATA_DIR "/example.zone\"," + " \"filetype\": \"sqlite3\"}]}]}"), false)); +} + } diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc index 73ab353fd2..8139d3359a 100644 --- a/src/bin/auth/tests/config_unittest.cc +++ b/src/bin/auth/tests/config_unittest.cc @@ -143,4 +143,13 @@ TEST_F(AuthConfigTest, listenAddressConfig) { EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options); } +TEST_F(AuthConfigTest, tcpRecvTimeoutConfig) { + configureAuthServer(server, Element::fromJSON( + "{ \"tcp_recv_timeout\": 123 }")); + EXPECT_EQ(123, dnss_.getTCPRecvTimeout()); + configureAuthServer(server, Element::fromJSON( + "{ \"tcp_recv_timeout\": 2000 }")); + EXPECT_EQ(2000, dnss_.getTCPRecvTimeout()); +} + } diff --git a/src/lib/asiodns/dns_server.h b/src/lib/asiodns/dns_server.h index 119aa66608..9f3bb6dd47 100644 --- a/src/lib/asiodns/dns_server.h +++ b/src/lib/asiodns/dns_server.h @@ -81,7 +81,7 @@ public: /// \brief Stop current running server virtual void stop() { self_->stop();} - /// \brief Resume processing of the server coroutine after an + /// \brief Resume processing of the server coroutine after an /// asynchronous call (e.g., to the DNS Lookup provider) has completed. /// /// \param done If true, this signals the system there is an answer @@ -99,6 +99,8 @@ public: virtual DNSServer* clone() { return (self_->clone()); } //@} + virtual void setTCPRecvTimeout(size_t) {} + protected: /// \brief Lookup handler object. /// diff --git a/src/lib/asiodns/dns_service.cc b/src/lib/asiodns/dns_service.cc index 2cfdea570e..11c86b0fb1 100644 --- a/src/lib/asiodns/dns_service.cc +++ b/src/lib/asiodns/dns_service.cc @@ -53,13 +53,25 @@ public: SimpleCallback* checkin_; DNSLookup* lookup_; DNSAnswer* answer_; + size_t tcp_recv_timeout_; template void addServerFromFD(int fd, int af) { Ptr server(new Server(io_service_.get_io_service(), fd, af, checkin_, lookup_, answer_)); + server->setTCPRecvTimeout(tcp_recv_timeout_); (*server)(); servers_.push_back(server); } + + void setTCPRecvTimeout(size_t timeout) { + // Store it for future tcp connections + tcp_recv_timeout_ = timeout; + // Update existing (TCP) Servers + std::vector::iterator it = servers_.begin(); + for (; it != servers_.end(); ++it) { + (*it)->setTCPRecvTimeout(timeout); + } + } }; DNSService::DNSService(IOService& io_service, SimpleCallback* checkin, @@ -99,5 +111,10 @@ DNSService::clearServers() { impl_->servers_.clear(); } +void +DNSService::setTCPRecvTimeout(size_t timeout) { + impl_->setTCPRecvTimeout(timeout); +} + } // namespace asiodns } // namespace isc diff --git a/src/lib/asiodns/dns_service.h b/src/lib/asiodns/dns_service.h index 8f2f6d7fee..e65354fefe 100644 --- a/src/lib/asiodns/dns_service.h +++ b/src/lib/asiodns/dns_service.h @@ -84,6 +84,9 @@ public: ServerFlag options = SERVER_DEFAULT) = 0; virtual void clearServers() = 0; + /// Sets the timeout TODO + virtual void setTCPRecvTimeout(size_t timeout) = 0; + virtual asiolink::IOService& getIOService() = 0; }; @@ -187,6 +190,7 @@ public: /// \return IOService object for this DNS service. virtual asiolink::IOService& getIOService() { return (io_service_);} + virtual void setTCPRecvTimeout(size_t timeout); private: DNSServiceImpl* impl_; asiolink::IOService& io_service_; diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc index 3f9e2412d2..616ca6720e 100644 --- a/src/lib/asiodns/tcp_server.cc +++ b/src/lib/asiodns/tcp_server.cc @@ -47,6 +47,8 @@ namespace asiodns { /// The following functions implement the \c TCPServer class. /// /// The constructor +// timeout is initialized to be sure, but it should be updated +// quite immediately anyway TCPServer::TCPServer(io_service& io_service, int fd, int af, const SimpleCallback* checkin, const DNSLookup* lookup, @@ -70,6 +72,9 @@ TCPServer::TCPServer(io_service& io_service, int fd, int af, // it isc_throw(IOError, exception.what()); } + // Set it to some value. It should be set to the right one + // immediately, but set something non-zero just in case. + tcp_recv_timeout_.reset(new size_t(1000)); } namespace { @@ -82,7 +87,6 @@ namespace { { if (error != asio::error::operation_aborted) { socket.cancel(); - } else { } } } @@ -130,7 +134,8 @@ TCPServer::operator()(asio::error_code ec, size_t length) { data_.reset(new char[MAX_LENGTH]); timeout_.reset(new asio::deadline_timer(io_)); - timeout_->expires_from_now(boost::posix_time::milliseconds(1000)); + timeout_->expires_from_now( + boost::posix_time::milliseconds(*tcp_recv_timeout_)); timeout_->async_wait(boost::bind(&do_timeout, boost::ref(*socket_), asio::placeholders::error)); diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h index 1d95a30b2c..7675daf332 100644 --- a/src/lib/asiodns/tcp_server.h +++ b/src/lib/asiodns/tcp_server.h @@ -61,6 +61,16 @@ public: return (s); } + /// \brief Set the read timeout + /// + /// If the client does not send (all) query data within this + /// timeframe, the connection is dropped + /// + /// \param timeout in milliseconds + virtual void setTCPRecvTimeout(size_t timeout) { + *tcp_recv_timeout_ = timeout; + } + private: enum { MAX_LENGTH = 65535 }; static const size_t TCP_MESSAGE_LENGTHSIZE = 2; @@ -128,6 +138,11 @@ private: // that outlives the operator() call and is copyable (for CORO_FORK) // even though it is only set after fork boost::shared_ptr timeout_; + + // Timeout value to use in the timer; + // this, too, is a pointer, so that it can be updated whithout restarting + // the server + boost::shared_ptr tcp_recv_timeout_; }; } // namespace asiodns diff --git a/src/lib/asiodns/tests/dns_server_unittest.cc b/src/lib/asiodns/tests/dns_server_unittest.cc index e728d4eb77..412dd59a9f 100644 --- a/src/lib/asiodns/tests/dns_server_unittest.cc +++ b/src/lib/asiodns/tests/dns_server_unittest.cc @@ -259,7 +259,7 @@ class TCPClient : public SimpleClient { static const unsigned int SERVER_TIME_OUT = 2; TCPClient(asio::io_service& service, const ip::tcp::endpoint& server) : SimpleClient(service, SERVER_TIME_OUT), - send_data_(true), send_data_len_(true) + send_data_delay_(0), send_data_len_delay_(0) { server_ = server; socket_.reset(new ip::tcp::socket(service)); @@ -281,14 +281,12 @@ class TCPClient : public SimpleClient { std::string(received_data_ + 2)); } - // if set to false, does not actually send data length - void setSendDataLen(bool send_data_len) { - send_data_len_ = send_data_len; + void setSendDataLenDelay(size_t send_data_len_delay) { + send_data_len_delay_ = send_data_len_delay; } - // if set to false, does not actually send data - void setSendData(bool send_data) { - send_data_ = send_data; + void setSendDataDelay(size_t send_data_delay) { + send_data_delay_ = send_data_delay; } private: @@ -297,8 +295,9 @@ class TCPClient : public SimpleClient { } void connectHandler(const asio::error_code& error) { - if (!error && send_data_len_) { + if (!error) { data_to_send_len_ = htons(data_to_send_len_); + sleep(send_data_len_delay_); socket_->async_send(buffer(&data_to_send_len_, 2), boost::bind(&TCPClient::sendMessageBodyHandler, this, _1, _2)); @@ -308,7 +307,8 @@ class TCPClient : public SimpleClient { void sendMessageBodyHandler(const asio::error_code& error, size_t send_bytes) { - if (!error && send_bytes == 2 && send_data_) { + if (!error && send_bytes == 2 && send_data_len_delay_ == 0) { + sleep(send_data_delay_); socket_->async_send(buffer(data_to_send_.c_str(), data_to_send_.size() + 1), boost::bind(&TCPClient::finishSendHandler, this, _1, _2)); @@ -327,8 +327,11 @@ class TCPClient : public SimpleClient { ip::tcp::endpoint server_; std::string data_to_send_; uint16_t data_to_send_len_; - bool send_data_; - bool send_data_len_; + + // if 0, send body immediately + // if >0, send after the delay (in seconds) + size_t send_data_delay_; + size_t send_data_len_delay_; }; // \brief provide the context which including two clients and @@ -579,7 +582,8 @@ TYPED_TEST(DNSServerTest, stopTCPServerAfterOneQuery) { } TYPED_TEST(DNSServerTest, TCPTimeoutOnLen) { - this->tcp_client_->setSendDataLen(false); + this->tcp_server_->setTCPRecvTimeout(100); + this->tcp_client_->setSendDataLenDelay(2); this->testStopServerByStopper(this->tcp_server_, this->tcp_client_, this->tcp_client_); EXPECT_EQ("", this->tcp_client_->getReceivedData()); @@ -587,11 +591,23 @@ TYPED_TEST(DNSServerTest, TCPTimeoutOnLen) { } TYPED_TEST(DNSServerTest, TCPTimeout) { - this->tcp_client_->setSendData(false); + // set delay higher than timeout + this->tcp_server_->setTCPRecvTimeout(100); + this->tcp_client_->setSendDataDelay(2); this->testStopServerByStopper(this->tcp_server_, this->tcp_client_, this->tcp_client_); EXPECT_EQ("", this->tcp_client_->getReceivedData()); - EXPECT_FALSE(this->serverStopSucceed()); + EXPECT_TRUE(this->serverStopSucceed()); +} + +TYPED_TEST(DNSServerTest, TCPNoTimeout) { + // set delay lower than timeout + this->tcp_server_->setTCPRecvTimeout(3000); + this->tcp_client_->setSendDataDelay(1); + this->testStopServerByStopper(this->tcp_server_, this->tcp_client_, + this->tcp_client_); + EXPECT_EQ("BIND10 is awesome", this->tcp_client_->getReceivedData()); + EXPECT_TRUE(this->serverStopSucceed()); } // Test whether tcp server stopped successfully before server start to serve diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h index b5def4badb..3028d7f077 100644 --- a/src/lib/testutils/mockups.h +++ b/src/lib/testutils/mockups.h @@ -138,9 +138,18 @@ public: return (udp_fd_params_); } + virtual void setTCPRecvTimeout(size_t timeout) { + tcp_recv_timeout_ = timeout; + } + + size_t getTCPRecvTimeout() { + return tcp_recv_timeout_; + } + private: std::vector > tcp_fd_params_; std::vector udp_fd_params_; + size_t tcp_recv_timeout_; }; // A nonoperative DNSServer object to be used in calls to processMessage(). From 6efd035f6178974adb48ace599f6d2335c0afd7e Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 29 Aug 2012 18:01:01 +0200 Subject: [PATCH 052/148] [1959] Added support for packet templates. --- tests/tools/perfdhcp/localized_option.h | 60 +- tests/tools/perfdhcp/perf_pkt4.cc | 10 +- tests/tools/perfdhcp/perf_pkt4.h | 27 + tests/tools/perfdhcp/perf_pkt6.cc | 8 + tests/tools/perfdhcp/perf_pkt6.h | 26 + tests/tools/perfdhcp/pkt_transform.cc | 13 +- tests/tools/perfdhcp/pkt_transform.h | 28 + .../perfdhcp/templates/discover-example.hex | 1 + .../perfdhcp/templates/request4-example.hex | 1 + .../perfdhcp/templates/request6-example.hex | 1 + .../perfdhcp/templates/solicit-example.hex | 1 + tests/tools/perfdhcp/test_control.cc | 623 +++++++++++++++--- tests/tools/perfdhcp/test_control.h | 160 ++++- .../perfdhcp/tests/test_control_unittest.cc | 95 ++- 14 files changed, 922 insertions(+), 132 deletions(-) create mode 100644 tests/tools/perfdhcp/templates/discover-example.hex create mode 100644 tests/tools/perfdhcp/templates/request4-example.hex create mode 100644 tests/tools/perfdhcp/templates/request6-example.hex create mode 100644 tests/tools/perfdhcp/templates/solicit-example.hex diff --git a/tests/tools/perfdhcp/localized_option.h b/tests/tools/perfdhcp/localized_option.h index 5374684f89..f93089fbad 100644 --- a/tests/tools/perfdhcp/localized_option.h +++ b/tests/tools/perfdhcp/localized_option.h @@ -16,6 +16,8 @@ #define __LOCALIZED_OPTION_H #include +#include +#include namespace isc { namespace perfdhcp { @@ -51,7 +53,7 @@ public: uint16_t type, const dhcp::OptionBuffer& data) : dhcp::Option(u, type, data), - offset_(0) { + offset_(0), option_valid_(true) { } @@ -66,7 +68,49 @@ public: const dhcp::OptionBuffer& data, const size_t offset) : dhcp::Option(u, type, data), - offset_(offset) { + offset_(offset), option_valid_(true) { + } + + /// \brief Copy constructor, creates LocalizedOption from Option6IA. + /// + /// This copy constructor creates regular option from Option6IA. + /// The data from Option6IA data members are copied to + /// option buffer in appropriate sequence. + /// + /// \param opt_ia option to be copied. + /// \param offset location of the option in a packet. + LocalizedOption(const boost::shared_ptr& opt_ia, + const size_t offset) : + dhcp::Option(Option::V6, 0, dhcp::OptionBuffer()), + offset_(offset), option_valid_(false) { + // If given option is NULL we will mark this new option + // as invalid. User may query if option is valid when + // object is created. + if (opt_ia) { + // Set universe and type. + universe_ = opt_ia->getUniverse(); + type_ = opt_ia->getType(); + util::OutputBuffer buf(opt_ia->len() - opt_ia->getHeaderLen()); + try { + // Try to pack option data into the temporary buffer. + opt_ia->pack(buf); + if (buf.getLength() > 0) { + const char* buf_data = static_cast(buf.getData()); + // Option has been packed along with option type flag + // and transaction id so we have to skip first 4 bytes + // when copying temporary buffer option buffer. + data_.assign(buf_data + 4, buf_data + buf.getLength()); + } + option_valid_ = true; + } catch (const Exception&) { + // If there was an exception somewhere when packing + // the data into the buffer we assume that option is + // not valid and should not be used. + option_valid_ = false; + } + } else { + option_valid_ = false; + } } /// \brief Constructor, sets default (0) option offset @@ -84,7 +128,7 @@ public: dhcp::OptionBufferConstIter first, dhcp::OptionBufferConstIter last) : dhcp::Option(u, type, first, last), - offset_(0) { + offset_(0), option_valid_(true) { } @@ -104,7 +148,7 @@ public: dhcp::OptionBufferConstIter first, dhcp::OptionBufferConstIter last, const size_t offset) : dhcp::Option(u, type, first, last), - offset_(offset) { + offset_(offset), option_valid_(true) { } /// \brief Returns offset of an option in a DHCP packet. @@ -112,8 +156,16 @@ public: /// \return option offset in a packet size_t getOffset() const { return offset_; }; + /// \brief Checks if option is valid. + /// + /// \return true, if option is valid. + virtual bool valid() { + return (Option::valid() && option_valid_); + } + private: size_t offset_; ///< Offset of DHCP option in a packet + bool option_valid_; ///< Is option valid. }; diff --git a/tests/tools/perfdhcp/perf_pkt4.cc b/tests/tools/perfdhcp/perf_pkt4.cc index 3f733afacc..3ccef94e98 100644 --- a/tests/tools/perfdhcp/perf_pkt4.cc +++ b/tests/tools/perfdhcp/perf_pkt4.cc @@ -16,7 +16,6 @@ #include #include "perf_pkt4.h" -#include "pkt_transform.h" using namespace std; using namespace isc; @@ -58,5 +57,14 @@ PerfPkt4::rawUnpack() { return (res); } +void +PerfPkt4::writeAt(size_t dest_pos, + std::vector::iterator first, + std::vector::iterator last) { + return (PktTransform::writeAt(data_, dest_pos, first, last)); +} + + + } // namespace perfdhcp } // namespace isc diff --git a/tests/tools/perfdhcp/perf_pkt4.h b/tests/tools/perfdhcp/perf_pkt4.h index f4cc440773..1a19a08749 100644 --- a/tests/tools/perfdhcp/perf_pkt4.h +++ b/tests/tools/perfdhcp/perf_pkt4.h @@ -20,6 +20,7 @@ #include #include "localized_option.h" +#include "pkt_transform.h" namespace isc { namespace perfdhcp { @@ -102,11 +103,37 @@ public: /// \return false If unpack operation failed. bool rawUnpack(); + /// \brief Replace contents of buffer with data. + /// + /// Function replaces part of the buffer with data from vector. + /// + /// \param dest_pos position in buffer where data is replaced. + /// \param first beginning of data range in source vector. + /// \param last end of data range in source vector. + void writeAt(size_t dest_pos, + std::vector::iterator first, + std::vector::iterator last); + + + /// \brief Replace contents of buffer with value. + /// + /// Function replaces part of buffer with value. + /// + /// \param dest_pos position in buffer where value is + /// to be written. + /// \param val value to be written. + template + void writeValueAt(size_t dest_pos, T val) { + PktTransform::writeValueAt(data_, dest_pos, val); + } + private: size_t transid_offset_; ///< transaction id offset }; +typedef boost::shared_ptr PerfPkt4Ptr; + } // namespace perfdhcp } // namespace isc diff --git a/tests/tools/perfdhcp/perf_pkt6.cc b/tests/tools/perfdhcp/perf_pkt6.cc index 24cfb931a9..56fe9dfd77 100644 --- a/tests/tools/perfdhcp/perf_pkt6.cc +++ b/tests/tools/perfdhcp/perf_pkt6.cc @@ -60,5 +60,13 @@ PerfPkt6::rawUnpack() { return (res); } +void +PerfPkt6::writeAt(size_t dest_pos, + std::vector::iterator first, + std::vector::iterator last) { + return (PktTransform::writeAt(data_, dest_pos, first, last)); +} + + } // namespace perfdhcp } // namespace isc diff --git a/tests/tools/perfdhcp/perf_pkt6.h b/tests/tools/perfdhcp/perf_pkt6.h index 94fe47bada..25fb4e53a4 100644 --- a/tests/tools/perfdhcp/perf_pkt6.h +++ b/tests/tools/perfdhcp/perf_pkt6.h @@ -20,6 +20,7 @@ #include #include "localized_option.h" +#include "pkt_transform.h" namespace isc { namespace perfdhcp { @@ -102,11 +103,36 @@ public: /// \return false if unpack operation failed. bool rawUnpack(); + /// \brief Replace contents of buffer with data. + /// + /// Function replaces part of the buffer with data from vector. + /// + /// \param dest_pos position in buffer where data is replaced. + /// \param first beginning of data range in source vector. + /// \param last end of data range in source vector. + void writeAt(size_t dest_pos, + std::vector::iterator first, + std::vector::iterator last); + + /// \brief Replace contents of buffer with value. + /// + /// Function replaces part of buffer with value. + /// + /// \param dest_pos position in buffer where value is + /// to be written. + /// \param val value to be written. + template + void writeValueAt(size_t dest_pos, T val) { + PktTransform::writeValueAt(data_, dest_pos, val); + } + private: size_t transid_offset_; ///< transaction id offset }; +typedef boost::shared_ptr PerfPkt6Ptr; + } // namespace perfdhcp } // namespace isc diff --git a/tests/tools/perfdhcp/pkt_transform.cc b/tests/tools/perfdhcp/pkt_transform.cc index 5ed39bfc5f..d87ca19c3b 100644 --- a/tests/tools/perfdhcp/pkt_transform.cc +++ b/tests/tools/perfdhcp/pkt_transform.cc @@ -216,7 +216,18 @@ PktTransform::unpackOptions(const OptionBuffer& in_buffer, in_buffer.begin() + offset + opt_len); } } - + +void +PktTransform::writeAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos, + dhcp::OptionBuffer::iterator first, + dhcp::OptionBuffer::iterator last) { + int i = 0; + for (std::vector::iterator it = first; + it != last; + ++it, ++i) { + in_buffer[dest_pos + i] = *it; + } +} } // namespace perfdhcp } // namespace isc diff --git a/tests/tools/perfdhcp/pkt_transform.h b/tests/tools/perfdhcp/pkt_transform.h index 7fb19f48c4..e7665a2dc8 100644 --- a/tests/tools/perfdhcp/pkt_transform.h +++ b/tests/tools/perfdhcp/pkt_transform.h @@ -92,6 +92,33 @@ public: const size_t transid_offset, uint32_t& transid); + /// \brief Replace contents of buffer with vector. + /// + /// Function replaces data of the buffer with data from vector. + /// + /// \param in_buffer destination buffer. + /// \param dest_pos position in destination buffer. + /// \param first beginning of data range in source vector. + /// \param last end of data range in source vector. + static void writeAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos, + std::vector::iterator first, + std::vector::iterator last); + + /// \brief Replace contents of one vector with uint16 value. + /// + /// Function replaces data inside one vector with uint16_t value. + /// + /// \param in_buffer destination buffer. + /// \param dest_pos position in destination buffer. + /// \param val value to be written. + template + static void writeValueAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos, + T val) { + for (int i = 0; i < sizeof(T); ++i) { + in_buffer[dest_pos + i] = (val >> (sizeof(T) - 8 * i - 1)) & 0xFF; + } + } + private: /// \brief Replaces contents of options in a buffer. /// @@ -131,6 +158,7 @@ private: /// \throw isc::Unexpected if options unpack failed. static void unpackOptions(const dhcp::OptionBuffer& in_buffer, const dhcp::Option::OptionCollection& options); + }; } // namespace perfdhcp diff --git a/tests/tools/perfdhcp/templates/discover-example.hex b/tests/tools/perfdhcp/templates/discover-example.hex new file mode 100644 index 0000000000..9a6e5ea53d --- /dev/null +++ b/tests/tools/perfdhcp/templates/discover-example.hex @@ -0,0 +1 @@ +01010601008b45d200000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633501013707011c02030f060cff \ No newline at end of file diff --git a/tests/tools/perfdhcp/templates/request4-example.hex b/tests/tools/perfdhcp/templates/request4-example.hex new file mode 100644 index 0000000000..32447d6ba8 --- /dev/null +++ b/tests/tools/perfdhcp/templates/request4-example.hex @@ -0,0 +1 @@ +01010601007b23f800000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633204ac1001813501033604ac1001013707011c02030f060cff \ No newline at end of file diff --git a/tests/tools/perfdhcp/templates/request6-example.hex b/tests/tools/perfdhcp/templates/request6-example.hex new file mode 100644 index 0000000000..1e3e76f5e7 --- /dev/null +++ b/tests/tools/perfdhcp/templates/request6-example.hex @@ -0,0 +1 @@ +03da30c60001000e0001000117cf8e76000c010203060002000e0001000117cf8a5c080027a87b3400030028000000010000000a0000000e0005001820010db800010000000000000001b568000000be000000c8000800020000 \ No newline at end of file diff --git a/tests/tools/perfdhcp/templates/solicit-example.hex b/tests/tools/perfdhcp/templates/solicit-example.hex new file mode 100644 index 0000000000..41c5ad33a8 --- /dev/null +++ b/tests/tools/perfdhcp/templates/solicit-example.hex @@ -0,0 +1 @@ +015f4e650001000e0001000117cf8e76000c010203040003000c0000000100000e01000015180006000400170018000800020000 \ No newline at end of file diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index c58631f841..6da2549182 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -12,6 +12,8 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. + +#include #include #include #include @@ -25,8 +27,11 @@ #include #include #include +#include #include "test_control.h" #include "command_options.h" +#include "perf_pkt4.h" +#include "perf_pkt6.h" using namespace std; using namespace boost; @@ -91,13 +96,13 @@ TestControl::byte2Hex(const uint8_t b) const { const int b0 = b % 16; ostringstream stream; stream << std::hex << b1 << b0 << std::dec; - return stream.str(); + return (stream.str()); } bool TestControl::checkExitConditions() const { if (interrupted_) { - return(true); + return (true); } CommandOptions& options = CommandOptions::instance(); bool test_period_reached = false; @@ -117,9 +122,9 @@ TestControl::checkExitConditions() const { } if (test_period_reached) { if (testDiags('e')) { - std::cout << "Reached test period." << std::endl; + std::cout << "reached test-period." << std::endl; } - return(true); + return (true); } bool max_requests = false; @@ -153,9 +158,9 @@ TestControl::checkExitConditions() const { } if (max_requests) { if (testDiags('e')) { - std::cout << "Reached test period." << std::endl; + std::cout << "Reached max requests limit." << std::endl; } - return(true); + return (true); } // Check if we reached maximum number of drops of OFFER/ADVERTISE packets. @@ -191,7 +196,7 @@ TestControl::checkExitConditions() const { if (testDiags('e')) { std::cout << "Reached maximum drops number." << std::endl; } - return(true); + return (true); } // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets. @@ -236,20 +241,19 @@ TestControl::checkExitConditions() const { if (testDiags('e')) { std::cout << "Reached maximum percentage of drops." << std::endl; } - return(true); + return (true); } - - return(false); + return (false); } OptionPtr TestControl::factoryElapsedTime6(Option::Universe, uint16_t, const OptionBuffer& buf) { if (buf.size() == 2) { - return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf)); + return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf))); } else if (buf.size() == 0) { - return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, - OptionBuffer(2, 0))); + return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(2, 0)))); } isc_throw(isc::BadValue, "elapsed time option buffer size has to be 0 or 2"); @@ -259,7 +263,7 @@ OptionPtr TestControl::factoryGeneric(Option::Universe u, uint16_t type, const OptionBuffer& buf) { OptionPtr opt(new Option(u, type, buf)); - return opt; + return (opt); } OptionPtr @@ -274,13 +278,13 @@ TestControl::factoryIana6(Option::Universe, uint16_t, for (int i = 0; i < buf.size(); ++i) { buf_ia_na.push_back(buf[i]); } - return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)); + return (OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na))); } OptionPtr TestControl::factoryRapidCommit6(Option::Universe, uint16_t, const OptionBuffer&) { - return OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())); + return (OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer()))); } OptionPtr @@ -288,11 +292,11 @@ TestControl::factoryOptionRequestOption6(Option::Universe, uint16_t, const OptionBuffer&) { const uint8_t buf_array[] = { - D6O_NAME_SERVERS, - D6O_DOMAIN_SEARCH + 0, D6O_NAME_SERVERS, + 0, D6O_DOMAIN_SEARCH }; OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); - return OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)); + return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options))); } @@ -313,15 +317,15 @@ TestControl::factoryRequestList4(Option::Universe u, OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); OptionPtr opt(new Option(u, type, buf)); opt->setData(buf_with_options.begin(), buf_with_options.end()); - return opt; + return (opt); } std::vector -TestControl::generateMacAddress() const { +TestControl::generateMacAddress(uint8_t& randomized) const { CommandOptions& options = CommandOptions::instance(); uint32_t clients_num = options.getClientsNum(); if ((clients_num == 0) || (clients_num == 1)) { - return options.getMacPrefix(); + return (options.getMacPrefix()); } // Get the base MAC address. We are going to randomize part of it. std::vector mac_addr(options.getMacPrefix()); @@ -333,12 +337,14 @@ TestControl::generateMacAddress() const { // will guarantee that every client has exactly one random MAC // address assigned. r %= clients_num; + randomized = 0; // Randomize MAC address octets. for (std::vector::iterator it = mac_addr.end() - 1; it >= mac_addr.begin(); --it) { // Add the random value to the current octet. (*it) += r; + ++randomized; if (r < 256) { // If we are here it means that there is no sense // to randomize the remaining octets of MAC address @@ -350,24 +356,24 @@ TestControl::generateMacAddress() const { // byte of random value. r >>= 8; } - return mac_addr; + return (mac_addr); } std::vector -TestControl::generateDuid() const { +TestControl::generateDuid(uint8_t& randomized) const { CommandOptions& options = CommandOptions::instance(); uint32_t clients_num = options.getClientsNum(); if ((clients_num == 0) || (clients_num == 1)) { - return options.getDuidPrefix(); + return (options.getDuidPrefix()); } // Get the base DUID. We are going to randomize part of it. std::vector duid(options.getDuidPrefix()); - std::vector mac_addr(generateMacAddress()); + std::vector mac_addr(generateMacAddress(randomized)); duid.resize(duid.size() - mac_addr.size()); for (int i = 0; i < mac_addr.size(); ++i) { duid.push_back(mac_addr[i]); } - return duid; + return (duid); } uint64_t @@ -413,20 +419,28 @@ uint64_t TestControl::getRcvdPacketsNum(const ExchangeType xchg_type) const { uint8_t ip_version = CommandOptions::instance().getIpVersion(); if (ip_version == 4) { - return(stats_mgr4_->getRcvdPacketsNum(xchg_type)); + return (stats_mgr4_->getRcvdPacketsNum(xchg_type)); } - return(stats_mgr6_-> - getRcvdPacketsNum(static_cast(xchg_type))); + return (stats_mgr6_-> + getRcvdPacketsNum(static_cast(xchg_type))); } uint64_t TestControl::getSentPacketsNum(const ExchangeType xchg_type) const { uint8_t ip_version = CommandOptions::instance().getIpVersion(); if (ip_version == 4) { - return(stats_mgr4_->getSentPacketsNum(xchg_type)); + return (stats_mgr4_->getSentPacketsNum(xchg_type)); } - return(stats_mgr6_-> - getSentPacketsNum(static_cast(xchg_type))); + return (stats_mgr6_-> + getSentPacketsNum(static_cast(xchg_type))); +} + +TestControl::TemplateBuffer +TestControl::getTemplateBuffer(const size_t idx) const { + if (template_buffers_.size() > idx) { + return (template_buffers_[idx]); + } + return (TemplateBuffer()); } void @@ -436,13 +450,13 @@ TestControl::handleInterrupt(int) { void TestControl::initPacketTemplates() { + template_buffers_.clear(); CommandOptions& options = CommandOptions::instance(); std::vector template_files = options.getTemplateFiles(); for (std::vector::const_iterator it = template_files.begin(); it != template_files.end(); ++it) { - - std::cout << "Open file " << *it << std::endl; + readPacketTemplate(*it); } } @@ -565,7 +579,7 @@ TestControl::openSocket() const { } } - return(sock); + return (sock); } void @@ -574,7 +588,6 @@ TestControl::printDiagnostics() const { if (testDiags('a')) { // Print all command line parameters. options.printCommandLine(); - // Print MAC and DUID. std::cout << "Set MAC to " << vector2Hex(options.getMacPrefix(), "::") << std::endl; @@ -661,7 +674,38 @@ TestControl::vector2Hex(const std::vector& vec, stream << separator << byte2Hex(*it); } } - return(stream.str()); + return (stream.str()); +} + +void +TestControl::readPacketTemplate(const std::string& file_name) { + std::ifstream temp_file; + temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate); + if (!temp_file.is_open()) { + isc_throw(BadValue, "unable to open template file " << file_name); + } + std::ifstream::pos_type temp_size = temp_file.tellg(); + if (temp_size % 2 != 0) { + temp_file.close(); + isc_throw(BadValue, "odd number of digits in template file"); + } + temp_file.seekg(0, ios::beg); + std::vector hex_digits(temp_size); + std::vector binary_stream; + temp_file.read(&hex_digits[0], temp_size); + temp_file.close(); + for (int i = 0; i < hex_digits.size(); i += 2) { + if (!isxdigit(hex_digits[i]) || !isxdigit(hex_digits[i+1])) { + isc_throw(BadValue, "the '" << hex_digits[i] << hex_digits[i+1] + << "' is not hexadecimal digit"); + } + stringstream s; + s << "0x" << hex_digits[i] << hex_digits[i+1]; + int b; + s >> std::hex >> b; + binary_stream.push_back(static_cast(b)); + } + template_buffers_.push_back(binary_stream); } void @@ -673,7 +717,11 @@ TestControl::receivePacket4(const TestControlSocket& socket, CommandOptions::ExchangeMode xchg_mode = CommandOptions::instance().getExchangeMode(); if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) { - sendRequest4(socket, pkt4); + if (template_buffers_.size() < 2) { + sendRequest4(socket, discover_pkt4, pkt4); + } else { + sendRequest4(socket, template_buffers_[1], discover_pkt4, pkt4); + } } } else if (pkt4->getType() == DHCPACK) { stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4); @@ -690,7 +738,11 @@ TestControl::receivePacket6(const TestControlSocket& socket, CommandOptions::ExchangeMode xchg_mode = CommandOptions::instance().getExchangeMode(); if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) { - sendRequest6(socket, solicit_pkt6, pkt6); + if (template_buffers_.size() < 2) { + sendRequest6(socket, solicit_pkt6, pkt6); + } else { + sendRequest6(socket, template_buffers_[1], solicit_pkt6, pkt6); + } } } else if (packet_type == DHCPV6_REPLY) { stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6); @@ -740,6 +792,7 @@ TestControl::registerOptionFactories4() const { LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_MESSAGE_TYPE, &TestControl::factoryGeneric); + // DHCP_SERVER_IDENTIFIER option factory. LibDHCP::OptionFactoryRegister(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, &TestControl::factoryGeneric); @@ -755,21 +808,27 @@ void TestControl::registerOptionFactories6() const { static bool factories_registered = false; if (!factories_registered) { + // D60_ELAPSED_TIME LibDHCP::OptionFactoryRegister(Option::V6, D6O_ELAPSED_TIME, &TestControl::factoryElapsedTime6); + // D6O_RAPID_COMMIT LibDHCP::OptionFactoryRegister(Option::V6, D6O_RAPID_COMMIT, &TestControl::factoryRapidCommit6); + // D6O_ORO (option request option) factory. LibDHCP::OptionFactoryRegister(Option::V6, D6O_ORO, &TestControl::factoryOptionRequestOption6); + // D6O_CLIENTID option factory. LibDHCP::OptionFactoryRegister(Option::V6, D6O_CLIENTID, &TestControl::factoryGeneric); + // D6O_SERVERID option factory. LibDHCP::OptionFactoryRegister(Option::V6, D6O_SERVERID, &TestControl::factoryGeneric); + // D6O_IA_NA option factory. LibDHCP::OptionFactoryRegister(Option::V6, D6O_IA_NA, &TestControl::factoryIana6); @@ -821,39 +880,57 @@ TestControl::run() { "command options must be parsed before running a test"); } + // Diagnostics is command line options mainly. printDiagnostics(); - + // Option factories have to be registered. registerOptionFactories(); TestControlSocket socket(openSocket()); - // Initialize packet templates. initPacketTemplates(); - // Initialize randomization seed. if (options.isSeeded()) { srandom(options.getSeed()); } - // If user interrupts the program we will exit gracefully. signal(SIGINT, TestControl::handleInterrupt); - // Preload server with number of packets. const bool do_preload = true; for (int i = 0; i < options.getPreload(); ++i) { if (options.getIpVersion() == 4) { - sendDiscover4(socket, do_preload); + // No template buffer means no -T option specified. + // We will build packet ourselfs. + if (template_buffers_.size() == 0) { + sendDiscover4(socket, do_preload); + } else { + const uint8_t template_idx = 0; + sendDiscover4(socket, template_buffers_[template_idx], + do_preload); + } } else if (options.getIpVersion() == 6) { - sendSolicit6(socket, do_preload); + // No template buffer means no -T option specified. + // We will build packet ourselfs. + if (template_buffers_.size() == 0) { + sendSolicit6(socket, do_preload); + } else { + const uint8_t template_idx = 0; + sendSolicit6(socket, template_buffers_[template_idx], + do_preload); + } } } - + // Initialize Statistics Manager. Release previous if any. initializeStatsMgr(); - for (;;) { + // Calculate send due based on when last exchange was initiated. updateSendDue(); + // If test period finished, maximum number of packet drops + // has been reached or test has been interrupted we have to + // finish the test. if (checkExitConditions()) { break; } + // Calculate number of packets to be sent to stay + // catch up with rate. uint64_t packets_due = getNextExchangesNum(); if ((packets_due == 0) && testDiags('i')) { if (options.getIpVersion() == 4) { @@ -866,19 +943,36 @@ TestControl::run() { // @todo: set non-zero timeout for packets once we implement // microseconds timeout in IfaceMgr. receivePackets(socket); - + // Send packets. for (uint64_t i = packets_due; i > 0; --i) { if (options.getIpVersion() == 4) { - sendDiscover4(socket); + // No template packets means that no -T option was specified. + // We have to build packets ourselfs. + if (template_buffers_.size() == 0) { + sendDiscover4(socket); + } else { + const uint8_t template_idx = 0; + sendDiscover4(socket, template_buffers_[template_idx]); + } } else { - sendSolicit6(socket); + // No template packets means that no -T option was specified. + // We have to build packets ourselfs. + if (template_buffers_.size() == 0) { + sendSolicit6(socket); + } else { + const uint8_t template_idx = 0; + sendSolicit6(socket, template_buffers_[template_idx]); + } } } + // Report delay means that user requested printing number + // of sent/received/dropped packets repeatedly. if (options.getReportDelay() > 0) { printIntermediateStats(); } } printStats(); + // Print server id. if (testDiags('s') && (first_packet_serverid_.size() > 0)) { std::cout << "Server id: " << vector2Hex(first_packet_serverid_) << std::endl; } @@ -893,7 +987,8 @@ TestControl::sendDiscover4(const TestControlSocket& socket, const bool preload /*= false*/) { last_sent_ = microsec_clock::universal_time(); // Generate the MAC address to be passed in the packet. - std::vector mac_address = generateMacAddress(); + uint8_t randomized = 0; + std::vector mac_address = generateMacAddress(randomized); // Generate trasnaction id to be set for the new exchange. const uint32_t transid = generateTransid(); Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, transid)); @@ -911,6 +1006,10 @@ TestControl::sendDiscover4(const TestControlSocket& socket, // Set client's and server's ports as well as server's address, // and local (relay) address. setDefaults4(socket, pkt4); + + // Set hardware address + pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address); + pkt4->pack(); IfaceMgr::instance().send(pkt4); if (!preload) { @@ -922,8 +1021,70 @@ TestControl::sendDiscover4(const TestControlSocket& socket, } } +void +TestControl::sendDiscover4(const TestControlSocket& socket, + const std::vector& template_buf, + const bool preload /* = false */) { + // last_sent_ has to be updated for each function that initiates + // new transaction. The packet exchange synchronization relies on this. + last_sent_ = microsec_clock::universal_time(); + CommandOptions& options = CommandOptions::instance(); + // Get the first argument if mulitple the same arguments specified + // in the command line. First one refers to DISCOVER packets. + const uint8_t arg_idx = 0; + // Generate the MAC address to be passed in the packet. + uint8_t randomized = 0; + std::vector mac_address = generateMacAddress(randomized); + // Generate trasnaction id to be set for the new exchange. + const uint32_t transid = generateTransid(); + // Get transaction id offset. + size_t transid_offset = DHCPV4_TRANSID_OFFSET; + if (options.getTransactionIdOffset().size() > arg_idx) { + transid_offset = options.getTransactionIdOffset()[arg_idx]; + } + // Calculate randomization offset. + size_t rand_offset = DHCPV4_RANDOMIZATION_OFFSET; + if (options.getRandomOffset().size() > arg_idx) { + rand_offset = options.getRandomOffset()[arg_idx]; + } + // We need to go back by HW_ETHER_LEN (MAC address length) + // because this offset points to last octet of MAC address. + rand_offset -= HW_ETHER_LEN + 1; + // Create temporary buffer with template contents. We will + // modify this temporary buffer but we don't want to modify + // the original template. + std::vector in_buf(template_buf.begin(), + template_buf.end()); + // Check if we are not going out of bounds. + if (rand_offset + HW_ETHER_LEN > in_buf.size()) { + isc_throw(OutOfRange, "randomization offset is out of bounds"); + } + PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(), + transid_offset, + transid)); + + // Replace MAC address in the template with actual MAC address. + pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end()); + // Create a packet from the temporary buffer. + setDefaults4(socket, static_pointer_cast(pkt4)); + // Pack the input packet buffer to output buffer so as it can + // be sent to server. + pkt4->rawPack(); + IfaceMgr::instance().send(static_pointer_cast(pkt4)); + if (!preload) { + if (!stats_mgr4_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " + "hasn't been initialized"); + } + // Update packet stats. + stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, + static_pointer_cast(pkt4)); + } +} + void TestControl::sendRequest4(const TestControlSocket& socket, + const dhcp::Pkt4Ptr& discover_pkt4, const dhcp::Pkt4Ptr& offer_pkt4) { const uint32_t transid = generateTransid(); Pkt4Ptr pkt4(new Pkt4(DHCPREQUEST, transid)); @@ -958,7 +1119,7 @@ TestControl::sendRequest4(const TestControlSocket& socket, OptionPtr opt_requested_address = OptionPtr(new Option(Option::V4, DHO_DHCP_REQUESTED_ADDRESS, OptionBuffer())); - opt_requested_address->setUint32(yiaddr); + opt_requested_address->setUint32(static_cast(yiaddr)); pkt4->addOption(opt_requested_address); OptionPtr opt_parameter_list = Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST); @@ -966,6 +1127,15 @@ TestControl::sendRequest4(const TestControlSocket& socket, // Set client's and server's ports as well as server's address, // and local (relay) address. setDefaults4(socket, pkt4); + + // Set hardware address + const uint8_t* chaddr = offer_pkt4->getChaddr(); + std::vector mac_address(chaddr, chaddr + HW_ETHER_LEN); + pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address); + // Set elapsed time. + uint32_t elapsed_time = getElapsedTime(discover_pkt4, offer_pkt4); + pkt4->setSecs(static_cast(elapsed_time / 1000)); + // Prepare on wire data to send. pkt4->pack(); IfaceMgr::instance().send(pkt4); if (!stats_mgr4_) { @@ -975,6 +1145,124 @@ TestControl::sendRequest4(const TestControlSocket& socket, stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA, pkt4); } +void +TestControl::sendRequest4(const TestControlSocket& socket, + const std::vector& template_buf, + const dhcp::Pkt4Ptr& discover_pkt4, + const dhcp::Pkt4Ptr& offer_pkt4) { + CommandOptions& options = CommandOptions::instance(); + // Get the second argument if multiple the same arguments specified + // in the command line. Second one refers to REQUEST packets. + const uint8_t arg_idx = 1; + // Generate new transaction id. + const uint32_t transid = generateTransid(); + // Get transaction id offset. + size_t transid_offset = DHCPV4_TRANSID_OFFSET; + if (options.getTransactionIdOffset().size() > arg_idx) { + transid_offset = options.getTransactionIdOffset()[arg_idx]; + } + // Get the offset of MAC's last octet. + size_t rand_offset = DHCPV4_RANDOMIZATION_OFFSET; + if (options.getRandomOffset().size() > arg_idx) { + rand_offset = options.getRandomOffset()[arg_idx]; + } + // We need to go back by HW_ETHER_LEN (MAC address length) + // because this offset points to last octet of MAC address. + rand_offset -= HW_ETHER_LEN + 1; + // Create temporaru buffer from the template. + std::vector in_buf(template_buf.begin(), + template_buf.end()); + // Check if given randomization offset is not out of bounds. + if (rand_offset + HW_ETHER_LEN > in_buf.size()) { + isc_throw(OutOfRange, "randomization offset is out of bounds"); + } + + // Create packet from the temporary buffer. + PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(), + transid_offset, + transid)); + + // Set hardware address from OFFER packet received. + const uint8_t* chaddr = offer_pkt4->getChaddr(); + std::vector mac_address(chaddr, chaddr + HW_ETHER_LEN); + pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end()); + + // Set elapsed time. + size_t elp_offset = 0; + if (options.getElapsedTimeOffset() > 0) { + elp_offset = options.getElapsedTimeOffset(); + } + uint32_t elapsed_time = getElapsedTime(discover_pkt4, offer_pkt4); + pkt4->writeValueAt(elp_offset, + static_cast(elapsed_time / 1000)); + + // Get the actual server id offset. + size_t sid_offset = DHCPV4_SERVERID_OFFSET; + if (options.getServerIdOffset() > 0) { + sid_offset = options.getServerIdOffset(); + } + if (CommandOptions::instance().isUseFirst() && + (first_packet_serverid_.size() > 0)) { + boost::shared_ptr + opt_serverid(new LocalizedOption(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + first_packet_serverid_, + sid_offset)); + pkt4->addOption(opt_serverid); + } else { + // Copy the contents of server identifier received in + // OFFER packet to put this into REQUEST. + OptionPtr opt_serverid_offer = + offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER); + if (!opt_serverid_offer) { + isc_throw(BadValue, "there is no SERVER_IDENTIFIER option " + << "in OFFER message"); + } + boost::shared_ptr + opt_serverid(new LocalizedOption(Option::V4, + DHO_DHCP_SERVER_IDENTIFIER, + opt_serverid_offer->getData(), + sid_offset)); + pkt4->addOption(opt_serverid); + if (stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) { + first_packet_serverid_ = opt_serverid_offer->getData(); + } + } + + /// Set client address. + asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr(); + if (!yiaddr.getAddress().is_v4()) { + isc_throw(BadValue, "the YIADDR returned in OFFER packet is not " + " IPv4 address"); + } + + // Get the actual offset of requested ip. + size_t rip_offset = DHCPV4_REQUESTED_IP_OFFSET; + if (options.getRequestedIpOffset() > 0) { + rip_offset = options.getRequestedIpOffset(); + } + // Place requested IP option at specified position (rip_offset). + boost::shared_ptr + opt_requested_ip(new LocalizedOption(Option::V4, + DHO_DHCP_REQUESTED_ADDRESS, + OptionBuffer(), + rip_offset)); + // The IOAddress is castable to uint32_t and returns exactly what we need. + opt_requested_ip->setUint32(static_cast(yiaddr)); + pkt4->addOption(opt_requested_ip); + + setDefaults4(socket, static_pointer_cast(pkt4)); + // Prepare on-wire data. + pkt4->rawPack(); + IfaceMgr::instance().send(static_pointer_cast(pkt4)); + if (!stats_mgr4_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " + "hasn't been initialized"); + } + // Update packet stats. + stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA, + static_pointer_cast(pkt4)); +} void TestControl::sendRequest6(const TestControlSocket& socket, @@ -982,31 +1270,22 @@ TestControl::sendRequest6(const TestControlSocket& socket, const Pkt6Ptr& advertise_pkt6) { const uint32_t transid = generateTransid(); Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid)); - // Calculate elapsed time - ptime solicit_time = solicit_pkt6->getTimestamp(); - ptime advertise_time = advertise_pkt6->getTimestamp(); - if (solicit_time.is_not_a_date_time()) { - isc_throw(Unexpected, "timestamp was not set for SOLICIT packet"); - } - if (advertise_time.is_not_a_date_time()) { - isc_throw(Unexpected, "timestamp was not set for ADVERTISE packet"); - } - time_period period(solicit_time, advertise_time); - if (period.is_null()) { - pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME)); - } else { - OptionBuffer buf(); - const uint32_t elapsed_time = period.length().total_seconds(); - OptionPtr opt_elapsed_time = - Option::factory(Option::V6, D6O_ELAPSED_TIME); - opt_elapsed_time->setUint16(static_cast(elapsed_time)); - pkt6->addOption(opt_elapsed_time); - } + // Set elapsed time. + const uint32_t elapsed_time = + getElapsedTime(solicit_pkt6, advertise_pkt6); + OptionPtr opt_elapsed_time = + Option::factory(Option::V6, D6O_ELAPSED_TIME); + opt_elapsed_time->setUint16(static_cast(elapsed_time / 10)); + pkt6->addOption(opt_elapsed_time); + // Set client id. OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID); if (!opt_clientid) { isc_throw(Unexpected, "client id not found in received packet"); } pkt6->addOption(opt_clientid); + + // Use first flags indicates that we want to use the server + // id captured in fisrt packet. if (CommandOptions::instance().isUseFirst() && (first_packet_serverid_.size() > 0)) { pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID, @@ -1021,14 +1300,17 @@ TestControl::sendRequest6(const TestControlSocket& socket, } pkt6->addOption(opt_serverid); } + // Set IA_NA option. OptionPtr opt_ia_na = advertise_pkt6->getOption(D6O_IA_NA); if (!opt_ia_na) { isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received " "packet"); } pkt6->addOption(opt_ia_na); - setDefaults6(socket, pkt6); + // Set default packet data. + setDefaults6(socket, pkt6); + // Prepare on-wire data. pkt6->pack(); IfaceMgr::instance().send(pkt6); if (!stats_mgr6_) { @@ -1038,14 +1320,140 @@ TestControl::sendRequest6(const TestControlSocket& socket, stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RR, pkt6); } +void +TestControl::sendRequest6(const TestControlSocket& socket, + const std::vector& template_buf, + const Pkt6Ptr& solicit_pkt6, + const Pkt6Ptr& advertise_pkt6) { + CommandOptions& options = CommandOptions::instance(); + // Get the second argument if multiple the same arguments specified + // in the command line. Second one refers to REQUEST packets. + const uint8_t arg_idx = 1; + // Generate transaction id. + const uint32_t transid = generateTransid(); + // Get transaction id offset. + size_t transid_offset = DHCPV6_TRANSID_OFFSET; + if (options.getTransactionIdOffset().size() > arg_idx) { + transid_offset = options.getTransactionIdOffset()[arg_idx]; + } + PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(), + transid_offset, transid)); + // Set elapsed time. + size_t elp_offset = DHCPV6_ELAPSED_TIME_OFFSET; + if (options.getElapsedTimeOffset() > 0) { + elp_offset = options.getElapsedTimeOffset(); + } + uint32_t elapsed_time = + getElapsedTime(solicit_pkt6, advertise_pkt6); + boost::shared_ptr + opt_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME, + OptionBuffer(), elp_offset)); + opt_elapsed_time->setUint16(static_cast(elapsed_time / 10)); + pkt6->addOption(opt_elapsed_time); + + // Get the actual server id offset. + size_t sid_offset = DHCPV6_SERVERID_OFFSET; + if (options.getServerIdOffset() > 0) { + sid_offset = options.getServerIdOffset(); + } + if (CommandOptions::instance().isUseFirst() && + (first_packet_serverid_.size() > 0)) { + boost::shared_ptr + opt_serverid(new LocalizedOption(Option::V6, + D6O_SERVERID, + first_packet_serverid_, + sid_offset)); + pkt6->addOption(opt_serverid); + + } else { + // Copy the contents of server identifier received in + // ADVERTISE packet to put this into REQUEST. + OptionPtr opt_serverid_advertise = + advertise_pkt6->getOption(D6O_SERVERID); + if (!opt_serverid_advertise) { + isc_throw(BadValue, "there is no SERVERID option " + << "in ADVERTISE message"); + } + boost::shared_ptr + opt_serverid(new LocalizedOption(Option::V6, + D6O_SERVERID, + opt_serverid_advertise->getData(), + sid_offset)); + pkt6->addOption(opt_serverid); + if (stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) { + first_packet_serverid_ = opt_serverid_advertise->getData(); + } + } + // Set IA_NA + boost::shared_ptr opt_ia_na_advertise = + static_pointer_cast(advertise_pkt6->getOption(D6O_IA_NA)); + if (!opt_ia_na_advertise) { + isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received " + "packet"); + } + size_t addr_offset = DHCPV6_IA_NA_OFFSET; + if (options.getRequestedIpOffset() > 0) { + addr_offset = options.getRequestedIpOffset(); + } + boost::shared_ptr + opt_ia_na(new LocalizedOption(opt_ia_na_advertise, addr_offset)); + if (!opt_ia_na->valid()) { + isc_throw(BadValue, "Option IA_NA in advertise packet is invalid"); + } + pkt6->addOption(opt_ia_na); + // Set server id. + OptionPtr opt_serverid_advertise = advertise_pkt6->getOption(D6O_SERVERID); + if (!opt_serverid_advertise) { + isc_throw(Unexpected, "DHCPV6 SERVERID option not found in received " + "packet"); + } + size_t srvid_offset = DHCPV6_SERVERID_OFFSET; + if (options.getServerIdOffset() > 0) { + srvid_offset = options.getServerIdOffset(); + } + boost::shared_ptr + opt_serverid(new LocalizedOption(Option::V6, D6O_SERVERID, + opt_serverid_advertise->getData(), + srvid_offset)); + pkt6->addOption(opt_serverid); + // Get randomization offset. + size_t rand_offset = DHCPV6_RANDOMIZATION_OFFSET; + if (options.getRandomOffset().size() > arg_idx) { + rand_offset = options.getRandomOffset()[arg_idx]; + } + OptionPtr opt_clientid_advertise = advertise_pkt6->getOption(D6O_CLIENTID); + if (!opt_clientid_advertise) { + isc_throw(Unexpected, "DHCPV6 CLIENTID option not found in received packet"); + } + rand_offset -= (opt_clientid_advertise->len() - 1); + // Set client id. + boost::shared_ptr + opt_clientid(new LocalizedOption(Option::V6, D6O_CLIENTID, + opt_clientid_advertise->getData(), + rand_offset)); + pkt6->addOption(opt_clientid); + // Set default packet data. + setDefaults6(socket, pkt6); + // Prepare on wire data. + pkt6->rawPack(); + // Send packet. + IfaceMgr::instance().send(pkt6); + if (!stats_mgr6_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " + "hasn't been initialized"); + } + // Update packet stats. + stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RR, pkt6); + +} + void TestControl::sendSolicit6(const TestControlSocket& socket, const bool preload /*= false*/) { last_sent_ = microsec_clock::universal_time(); - // Generate the MAC address to be passed in the packet. - std::vector mac_address = generateMacAddress(); // Generate DUID to be passed to the packet - std::vector duid = generateDuid(); + uint8_t randomized = 0; + std::vector duid = generateDuid(randomized); // Generate trasnaction id to be set for the new exchange. const uint32_t transid = generateTransid(); Pkt6Ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid)); @@ -1072,6 +1480,58 @@ TestControl::sendSolicit6(const TestControlSocket& socket, } } +void +TestControl::sendSolicit6(const TestControlSocket& socket, + const std::vector& template_buf, + const bool preload /*= false*/) { + last_sent_ = microsec_clock::universal_time(); + CommandOptions& options = CommandOptions::instance(); + const int arg_idx = 0; + // Get transaction id offset. + size_t transid_offset = DHCPV6_TRANSID_OFFSET; + if (options.getTransactionIdOffset().size() > arg_idx) { + transid_offset = options.getTransactionIdOffset()[arg_idx]; + } + // Generate trasnaction id to be set for the new exchange. + const uint32_t transid = generateTransid(); + // Create packet. + PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(), + transid_offset, transid)); + if (!pkt6) { + isc_throw(Unexpected, "failed to create SOLICIT packet"); + } + size_t rand_offset = DHCPV6_RANDOMIZATION_OFFSET; + if (options.getRandomOffset().size() > arg_idx) { + rand_offset = options.getRandomOffset()[arg_idx]; + } + // randomized will pick number of bytes randomized so we can + // just use part of the generated duid and substitude a few bytes + /// in template. + uint8_t randomized = 0; + std::vector duid = generateDuid(randomized); + if (rand_offset > template_buf.size()) { + isc_throw(OutOfRange, "randomization offset is out of bounds"); + } + // Store random part of the DUID into the packet. + pkt6->writeAt(rand_offset - randomized + 1, + duid.end() - randomized, duid.end()); + + // Prepare on-wire data. + pkt6->rawPack(); + setDefaults6(socket, pkt6); + // Send solicit packet. + IfaceMgr::instance().send(pkt6); + if (!preload) { + if (!stats_mgr6_) { + isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 " + "hasn't been initialized"); + } + // Update packet stats. + stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6); + } +} + + void TestControl::setDefaults4(const TestControlSocket& socket, const Pkt4Ptr& pkt) { @@ -1090,9 +1550,6 @@ TestControl::setDefaults4(const TestControlSocket& socket, pkt->setLocalAddr(IOAddress(socket.getAddress())); // Set relay (GIADDR) address to local address. pkt->setGiaddr(IOAddress(socket.getAddress())); - std::vector mac = generateMacAddress(); - // Set hardware address - pkt->setHWAddr(HTYPE_ETHER, mac.size(), mac); // Pretend that we have one relay (which is us). pkt->setHops(1); } @@ -1119,9 +1576,9 @@ bool TestControl::testDiags(const char diag) const { std::string diags(CommandOptions::instance().getDiags()); if (diags.find(diag) != std::string::npos) { - return true; + return (true); } - return false; + return (false); } void diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 9b634ce5d7..2bace3a22e 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -48,20 +48,41 @@ namespace perfdhcp { class TestControl : public boost::noncopyable { public: - // Statistics Manager for DHCPv4. + /// Default transaction id offset. + static const size_t DHCPV4_TRANSID_OFFSET = 4; + /// Default offset of MAC's last octet. + static const size_t DHCPV4_RANDOMIZATION_OFFSET = 35; + /// Default elapsed time offset. + static const size_t DHCPV4_ELAPSED_TIME_OFFSET = 8; + /// Default server id offset. + static const size_t DHCPV4_SERVERID_OFFSET = 54; + /// Default requested ip offset. + static const size_t DHCPV4_REQUESTED_IP_OFFSET = 240; + /// Default DHCPV6 transaction id offset. + static const size_t DHCPV6_TRANSID_OFFSET = 1; + /// Default DHCPV6 randomization offset (last octet of DUID) + static const size_t DHCPV6_RANDOMIZATION_OFFSET = 21; + /// Default DHCPV6 elapsed time offset. + static const size_t DHCPV6_ELAPSED_TIME_OFFSET = 84; + /// Default DHCPV6 server id offset. + static const size_t DHCPV6_SERVERID_OFFSET = 22; + /// Default DHCPV6 IA_NA offset. + static const size_t DHCPV6_IA_NA_OFFSET = 40; + + /// Statistics Manager for DHCPv4. typedef StatsMgr StatsMgr4; - // Pointer to Statistics Manager for DHCPv4; + /// Pointer to Statistics Manager for DHCPv4; typedef boost::shared_ptr StatsMgr4Ptr; - // Statictics Manager for DHCPv6. + /// Statictics Manager for DHCPv6. typedef StatsMgr StatsMgr6; - // Pointer to Statistics Manager for DHCPv6. + /// Pointer to Statistics Manager for DHCPv6. typedef boost::shared_ptr StatsMgr6Ptr; - // Packet exchange type. + /// Packet exchange type. typedef StatsMgr<>::ExchangeType ExchangeType; - // Packet template buffer. + /// Packet template buffer. typedef std::vector TemplateBuffer; - //Packet template buffers list. - typedef std::list TemplateBufferList; + /// Packet template buffers list. + typedef std::vector TemplateBufferCollection; /// \brief Socket wrapper class. /// @@ -302,9 +323,10 @@ protected: /// from the MAC address, this function uses \ref generateMacAddress /// internally to randomize the DUID. /// + /// \param randomized number of bytes randomized. /// \throw isc::BadValue if \ref generateMacAddress throws. /// \return vector representing DUID. - std::vector generateDuid() const; + std::vector generateDuid(uint8_t& randomized) const; /// \brief Generate MAC address. /// @@ -315,10 +337,11 @@ protected: /// Based on this the random value is generated and added to /// the MAC address prefix (default MAC address). /// + /// \param randomized number of bytes randomized. /// \throw isc::BadValue if MAC address prefix (default or specified /// from the command line) has invalid size (expected 6 octets). /// \return generated MAC address. - std::vector generateMacAddress() const; + std::vector generateMacAddress(uint8_t& randomized) const; /// \brief generate transaction id. /// @@ -337,6 +360,21 @@ protected: /// \return number of exchanges to be started immediatelly. uint64_t getNextExchangesNum() const; + /// \brief Return template buffer. + /// + /// Method returns template buffer at specified index. + /// + /// \param idx index of template buffer. + /// \return reference to template buffer or empty buffer if index + /// is out of bounds. + TemplateBuffer getTemplateBuffer(const size_t idx) const; + + /// \brief Reads packet templates from files. + /// + /// Method iterates through all specified template files, reads + /// their content and stores it in class internal buffers + /// + /// \throw isc::BadValue if any of the template files does not exist void initPacketTemplates(); /// \brief Initializes Statistics Manager. @@ -448,9 +486,9 @@ protected: void registerOptionFactories() const; - /// \brief Resets internal state of the object. + /// \brief Resets internal state of the object. /// - /// Method resets internal state of the object. It has to be + /// Method resets internal state of the object. It has to be /// called before new test is started. void reset(); @@ -472,16 +510,46 @@ protected: void sendDiscover4(const TestControlSocket& socket, const bool preload = false); + /// \brief Send DHCPv4 DISCOVER message from template. + /// + /// Method sends DHCPv4 DISCOVER message from template. The + /// template data is exepcted to be in binary format. Provided + /// buffer is copied and parts of it are replaced with actual + /// data (e.g. MAC address, transaction id etc.). + /// + /// \param socket socket to be used to send the message. + /// \param template_buf buffer holding template packet. + /// \param preload preload mode, packets not included in statistics. + /// \throw isc::OutOfRange if randomization offset is out of bounds. + void sendDiscover4(const TestControlSocket& socket, + const std::vector& template_buf, + const bool preload = false); + /// \brief Send DHCPv4 REQUEST message. /// /// Method creates and sends DHCPv4 REQUEST message to the server. /// /// \param socket socket to be used to send message. + /// \param discover_pkt4 DISCOVER packet sent. /// \param offer_pkt4 OFFER packet object. /// \throw isc::Unexpected if unexpected error occured. /// \throw isc::InvalidOperation if Statistics Manager has not been /// initialized. void sendRequest4(const TestControlSocket& socket, + const dhcp::Pkt4Ptr& discover_pkt4, + const dhcp::Pkt4Ptr& offer_pkt4); + + /// \brief Send DHCPv4 REQUEST message from template. + /// + /// Method sends DHCPv4 REQUEST message from template. + /// + /// \param socket socket to be used to send message. + /// \param template_buf buffer holding template packet. + /// \param discover_pkt4 DISCOVER packet sent. + /// \param offer_pkt4 OFFER packet received. + void sendRequest4(const TestControlSocket& socket, + const std::vector& template_buf, + const dhcp::Pkt4Ptr& discover_pkt4, const dhcp::Pkt4Ptr& offer_pkt4); /// \brief Send DHCPv6 REQUEST message. @@ -506,6 +574,19 @@ protected: const dhcp::Pkt6Ptr& solicit_pkt6, const dhcp::Pkt6Ptr& advertise_pkt6); + /// \brief Send DHCPv6 REQUEST message from template. + /// + /// Method sends DHCPv6 REQUEST message from template. + /// + /// \param socket socket to be used to send message. + /// \param template_buf packet template buffer. + /// \param solicit_pkt6 SOLICIT packet object. + /// \param advertise_pkt6 ADVERTISE packet object. + void sendRequest6(const TestControlSocket& socket, + const std::vector& template_buf, + const dhcp::Pkt6Ptr& solicit_pkt6, + const dhcp::Pkt6Ptr& advertise_pkt6); + /// \brief Send DHCPv6 SOLICIT message. /// /// Method creates and sends DHCPv6 SOLICIT message to the server @@ -522,6 +603,17 @@ protected: void sendSolicit6(const TestControlSocket& socket, const bool preload = false); + /// \brief Send DHCPv6 SOLICIT message from template. + /// + /// Method sends DHCPv6 SOLICIT message from template. + /// + /// \param socket socket to be used to send the message. + /// \param template_buf packet template buffer. + /// \param preload mode, packets not included in statistics. + void sendSolicit6(const TestControlSocket& socket, + const std::vector& template_buf, + const bool preload = false); + /// \brief Set default DHCPv4 packet parameters. /// /// This method sets default parameters on the DHCPv4 packet: @@ -573,10 +665,27 @@ private: /// \return hex string. std::string byte2Hex(const uint8_t b) const; - /// \brief Generate transaction id using random function. + /// \brief Calculate elapsed time between two packets. /// - /// \return generated transaction id value. - static uint32_t generateTransidRandom(); + /// \param T Pkt4Ptr or Pkt6Ptr class. + /// \param pkt1 first packet. + /// \param pkt2 second packet. + /// \return elapsed time in milliseconds between pkt1 and pkt2. + template + uint32_t getElapsedTime(const T& pkt1, const T& pkt2) { + using namespace boost::posix_time; + ptime pkt1_time = pkt1->getTimestamp(); + ptime pkt2_time = pkt2->getTimestamp(); + if (pkt1_time.is_not_a_date_time() || + pkt2_time.is_not_a_date_time()) { + return (0); + } + time_period elapsed_period(pkt1_time, pkt2_time); + if (elapsed_period.is_null()) { + return (0); + } + return(elapsed_period.length().total_milliseconds()); + } /// \brief Get number of received packets. /// @@ -604,6 +713,18 @@ private: /// \param sig signal (ignored) static void handleInterrupt(int sig); + /// \brief Print main diagnostics data. + /// + /// Method prints main diagnostics data. + void printDiagnostics() const; + + /// \brief Read DHCP message template from file. + /// + /// Method reads DHCP message template from file and + /// converts it to binary format. Read data is appended + /// to template_buffers_ vector. + void readPacketTemplate(const std::string& file_name); + /// \brief Convert vector in hexadecimal string. /// /// \param vec vector to be converted. @@ -611,11 +732,6 @@ private: std::string vector2Hex(const std::vector& vec, const std::string& separator = "") const; - /// \brief Print main diagnostics data. - /// - /// Method prints main diagnostics data. - void printDiagnostics() const; - boost::posix_time::ptime send_due_; ///< Due time to initiate next chunk ///< of exchanges. boost::posix_time::ptime last_sent_; ///< Indicates when the last exchange @@ -629,10 +745,10 @@ private: TransidGeneratorPtr transid_gen_; ///< Transaction id generator. /// Buffer holiding server id received in first packet - dhcp::OptionBuffer first_packet_serverid_; + dhcp::OptionBuffer first_packet_serverid_; /// Packet template buffers. - TemplateBufferList template_buffers_; + TemplateBufferCollection template_buffers_; static bool interrupted_; ///< Is program interrupted. }; diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 2284042d58..d72cd0f755 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -60,7 +60,7 @@ public: /// /// \return generated transaction id. virtual uint32_t generate() { - return ++transid_; + return (++transid_); } private: uint32_t transid_; ///< Last generated transaction id. @@ -76,6 +76,8 @@ public: using TestControl::generateDuid; using TestControl::generateMacAddress; using TestControl::getNextExchangesNum; + using TestControl::getTemplateBuffer; + using TestControl::initPacketTemplates; using TestControl::initializeStatsMgr; using TestControl::openSocket; using TestControl::receivePacket4; @@ -109,7 +111,7 @@ public: static uint32_t generateTransidIncremental() { static uint32_t transid(1); - return ++transid; + return (++transid); } /// \brief Get local loopback interface name. @@ -134,11 +136,11 @@ public: ++addr_it) { if (asiolink::IOAddress("127.0.0.1").getAddress() == addr_it->getAddress()) { - return iface->getName(); + return (iface->getName()); } } } - return(""); + return (""); } /// \brief Match requested options in the buffer with given list. @@ -163,7 +165,7 @@ public: } } } - return matched_num; + return (matched_num); } /// \brief Calculate the maximum vectors' mismatch position. @@ -193,7 +195,7 @@ public: n %= 256; } } - return unequal_pos; + return (unequal_pos); } /// brief Test generation of mulitple DUIDs @@ -235,7 +237,8 @@ public: new_duid = old_duid; } else { std::swap(old_duid, new_duid); - new_duid = tc.generateDuid(); + uint8_t randomized = 0; + new_duid = tc.generateDuid(randomized); } // The DUID-LLT is expected to start with DUID_LLT value // of 1 and hardware ethernet type equal to 1 (HWETHER_TYPE). @@ -309,10 +312,19 @@ public: /// \param iterations_performed actual number of iterations. void testPkt4Exchange(int iterations_num, int receive_num, + bool use_templates, int& iterations_performed) const { int sock_handle = 0; NakedTestControl tc; tc.initializeStatsMgr(); + + // Use templates files to crate packets. + if (use_templates) { + tc.initPacketTemplates(); + ASSERT_GT(tc.getTemplateBuffer(0).size(), 0); + ASSERT_GT(tc.getTemplateBuffer(1).size(), 0); + } + // Incremental transaction id generator will generate // predictable values of transaction id for each iteration. // This is important because we need to simulate reponses @@ -326,7 +338,11 @@ public: TestControl::TestControlSocket sock(sock_handle); uint32_t transid = 0; for (int i = 0; i < iterations_num; ++i) { - ASSERT_NO_THROW(tc.sendDiscover4(sock)); + if (use_templates) { + ASSERT_NO_THROW(tc.sendDiscover4(sock, tc.getTemplateBuffer(0))); + } else { + ASSERT_NO_THROW(tc.sendDiscover4(sock)); + } ++transid; // Do not simulate responses for packets later // that specified as receive_num. This simulates @@ -359,10 +375,19 @@ public: /// \param iterations_performed actual number of iterations. void testPkt6Exchange(int iterations_num, int receive_num, + bool use_templates, int& iterations_performed) const { int sock_handle = 0; NakedTestControl tc; tc.initializeStatsMgr(); + + // Use templates files to crate packets. + if (use_templates) { + tc.initPacketTemplates(); + ASSERT_GT(tc.getTemplateBuffer(0).size(), 0); + ASSERT_GT(tc.getTemplateBuffer(1).size(), 0); + } + // Incremental transaction id generator will generate // predictable values of transaction id for each iteration. // This is important because we need to simulate reponses @@ -379,7 +404,11 @@ public: // Do not simulate responses for packets later // that specified as receive_num. This simulates // packet drops. - ASSERT_NO_THROW(tc.sendSolicit6(sock)); + if (use_templates) { + ASSERT_NO_THROW(tc.sendSolicit6(sock, tc.getTemplateBuffer(0))); + } else { + ASSERT_NO_THROW(tc.sendSolicit6(sock)); + } ++transid; if (i < receive_num) { boost::shared_ptr @@ -423,7 +452,8 @@ public: // Do many iterations to generate and test MAC address values. for (int i = 0; i < clients_num * 10; ++i) { // Generate new MAC address. - MacAddress new_mac(tc.generateMacAddress()); + uint8_t randomized = 0; + MacAddress new_mac(tc.generateMacAddress(randomized)); // Get the mismatch position (counting from the end) of // mismatched octet between previously generated MAC address // and current. @@ -471,7 +501,7 @@ private: offer->addOption(opt_msg_type); offer->addOption(opt_serverid); offer->updateTimestamp(); - return(offer); + return (offer); } boost::shared_ptr @@ -479,14 +509,15 @@ private: OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID)); NakedTestControl tc; - std::vector duid(tc.generateDuid()); + uint8_t randomized = 0; + std::vector duid(tc.generateDuid(randomized)); OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); boost::shared_ptr advertise(new Pkt6(DHCPV6_ADVERTISE, transid)); advertise->addOption(opt_ia_na); advertise->addOption(opt_serverid); advertise->addOption(opt_clientid); advertise->updateTimestamp(); - return(advertise); + return (advertise); } }; @@ -634,8 +665,8 @@ TEST_F(TestControlTest, Options6) { OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO)); // Prepare the reference buffer with requested options. const uint8_t requested_options[] = { - D6O_NAME_SERVERS, - D6O_DOMAIN_SEARCH + 0, D6O_NAME_SERVERS, + 0, D6O_DOMAIN_SEARCH }; OptionBuffer requested_options_ref(requested_options, @@ -751,22 +782,28 @@ TEST_F(TestControlTest, Packet4Exchange) { // The actual number of iterations will be stored in the // following variable. int iterations_performed = 0; - testPkt4Exchange(iterations_num, iterations_num, iterations_performed); + bool use_templates = false; + testPkt4Exchange(iterations_num, iterations_num, use_templates, iterations_performed); // The command line restricts the number of iterations to 10 // with -n 10 parameter. EXPECT_EQ(10, iterations_performed); // With the following command line we restrict the maximum // number of dropped packets to 20% of all. + // Use templates for this test. processCmdLine("perfdhcp -l " + loopback_iface - + " -r 100 -R 20 -n 20 -D 10% -L 10547 127.0.0.1"); + + " -r 100 -R 20 -n 20 -D 10% -L 10547" + + " -T ../templates/discover-example.hex" + + " -T ../templates/request4-example.hex" + + " 127.0.0.1"); // The number iterations is restricted by the percentage of // dropped packets (-D 10%). We also have to bump up the number // of iterations because the percentage limitation checks starts // at packet #10. We expect that at packet #12 the 10% threshold // will be reached. const int received_num = 10; - testPkt4Exchange(iterations_num, received_num, iterations_performed); + use_templates = true; + testPkt4Exchange(iterations_num, received_num, use_templates, iterations_performed); EXPECT_EQ(12, iterations_performed); } @@ -788,22 +825,38 @@ TEST_F(TestControlTest, Packet6Exchange) { int iterations_performed = 0; // Set number of received packets equal to number of iterations. // This simulates no packet drops. - testPkt6Exchange(iterations_num, iterations_num, iterations_performed); + bool use_templates = false; + testPkt6Exchange(iterations_num, iterations_num, use_templates, iterations_performed); // Actual number of iterations should be 10. EXPECT_EQ(10, iterations_performed); // The maximum number of dropped packets is 3 (because of -D 3). + use_templates = true; processCmdLine("perfdhcp -l " + loopback_iface - + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547 ::1"); + + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547" + + " -T ../templates/solicit-example.hex" + + " -T ../templates/request6-example.hex ::1"); // For the first 3 packets we are simulating responses from server. // For other packets we don't so packet as 4,5,6 will be dropped and // then test should be interrupted and actual number of iterations will // be 6. const int received_num = 3; - testPkt6Exchange(iterations_num, received_num, iterations_performed); + testPkt6Exchange(iterations_num, received_num, use_templates, iterations_performed); EXPECT_EQ(6, iterations_performed); } +TEST_F(TestControlTest, PacketTemplates) { + CommandOptions& options = CommandOptions::instance(); + NakedTestControl tc; + + ASSERT_NO_THROW( + processCmdLine("perfdhcp -l 127.0.0.1" + " -T ../templates/discover-example.hex" + " -T ../templates/request4-example.hex all") + ); + ASSERT_NO_THROW(tc.initPacketTemplates()); +} + TEST_F(TestControlTest, RateControl) { // We don't specify the exchange rate here so the aggressivity // value will determine how many packets are to be send each From 8fd8ed2aed8f309b655661389cf6ae043a854fe5 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Wed, 29 Aug 2012 18:01:24 +0000 Subject: [PATCH 053/148] [master] added missing header file and namespace for memcpy(). some stricter compilers require this. this fixes a build failure: http://git.bind10.isc.org/~tester/builder/BIND10/20120829105133-Solaris10-sparc-Sunstudio/logs/build.out okayed on jabber. --- src/lib/datasrc/memory/zone_data.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/datasrc/memory/zone_data.cc b/src/lib/datasrc/memory/zone_data.cc index 033af150c3..e2cbdef141 100644 --- a/src/lib/datasrc/memory/zone_data.cc +++ b/src/lib/datasrc/memory/zone_data.cc @@ -27,6 +27,7 @@ #include #include +#include #include // for the placement new #include @@ -94,7 +95,7 @@ NSEC3Data::create(util::MemorySegment& mem_sgmt, uint8_t hashalg, uint8_t* dp = param_data->getSaltBuf(); *dp++ = salt_len; if (salt_len > 0) { - memcpy(dp, &salt.at(0), salt_len); // use at for safety + std::memcpy(dp, &salt.at(0), salt_len); // use at for safety } return (param_data); From 5f5dd8f7dcfbb4423d53fe87ced200e4fdc9bef5 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Wed, 29 Aug 2012 12:20:44 -0700 Subject: [PATCH 054/148] [master] add cppcheck suppression rule for an intentional self-equivalence test okayed on jabber. --- src/lib/dns/tests/labelsequence_unittest.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc index 5eb49416d0..28f624aabd 100644 --- a/src/lib/dns/tests/labelsequence_unittest.cc +++ b/src/lib/dns/tests/labelsequence_unittest.cc @@ -180,6 +180,7 @@ TEST_F(LabelSequenceTest, equals_insensitive) { // operator==(). This is mostly trivial wrapper, so it should suffice to // check some basic cases. TEST_F(LabelSequenceTest, operatorEqual) { + // cppcheck-suppress duplicateExpression EXPECT_TRUE(ls1 == ls1); // self equivalence EXPECT_TRUE(ls1 == LabelSequence(n1)); // equivalent two different objects EXPECT_FALSE(ls1 == ls2); // non equivalent objects From 0f43c975990d11c7f0a071f3bd29836d28e08f4a Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Wed, 29 Aug 2012 17:00:01 -0500 Subject: [PATCH 055/148] [master] add missing header file distcheck failed since wasn't listed --- src/lib/datasrc/memory/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am index b8307c0a7e..ef46abe6e8 100644 --- a/src/lib/datasrc/memory/Makefile.am +++ b/src/lib/datasrc/memory/Makefile.am @@ -14,5 +14,6 @@ libdatasrc_memory_la_SOURCES = domaintree.h libdatasrc_memory_la_SOURCES += rdataset.h rdataset.cc libdatasrc_memory_la_SOURCES += rdata_serialization.h rdata_serialization.cc libdatasrc_memory_la_SOURCES += zone_data.h zone_data.cc +libdatasrc_memory_la_SOURCES += segment_object_holder.h libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc EXTRA_DIST = rdata_serialization_priv.cc From 4275cf4bdb01aecee2ef8beb52d40c320e2016b0 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Wed, 29 Aug 2012 17:54:22 -0700 Subject: [PATCH 056/148] [2180] s/Bind10/BIND 10/ --- src/lib/datasrc/datasrc_messages.mes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes index c78dab6e81..94b4d4249e 100644 --- a/src/lib/datasrc/datasrc_messages.mes +++ b/src/lib/datasrc/datasrc_messages.mes @@ -791,7 +791,7 @@ processing of the query. The database for SQLite data source was found empty. It is assumed this is the first run and it is being initialized with current schema. It'll still contain no data, but it will be ready for use. If this is indeed the first run of -Bind10, it is to be expected and completely harmless. If you just configured +BIND 10, it is to be expected and completely harmless. If you just configured a data source to point to an existing file and you see this, you may have misspelled the file name. From 88507052ccb7879ed422de7385e0cfe8aafc939d Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Thu, 30 Aug 2012 10:41:02 +0200 Subject: [PATCH 057/148] [2143]: MySQL DHCP benchmark now works with -Ofast --- tests/tools/dhcp-ubench/Makefile | 2 +- tests/tools/dhcp-ubench/mysql_ubench.cc | 25 ++++++++++++++++++++++++- tests/tools/dhcp-ubench/mysql_ubench.h | 17 +++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/tools/dhcp-ubench/Makefile b/tests/tools/dhcp-ubench/Makefile index 4be8fe773b..dbcfadd072 100644 --- a/tests/tools/dhcp-ubench/Makefile +++ b/tests/tools/dhcp-ubench/Makefile @@ -1,5 +1,5 @@ # Linux switches -CFLAGS=-g -O0 -Wall -pedantic -Wextra +CFLAGS=-g -Ofast -Wall -pedantic -Wextra # Mac OS: We don't use pedantic as Mac OS version of MySQL (5.5.24) does use long long (not part of ISO C++) #CFLAGS=-g -O0 -Wall -Wextra -I/opt/local/include diff --git a/tests/tools/dhcp-ubench/mysql_ubench.cc b/tests/tools/dhcp-ubench/mysql_ubench.cc index a3076597c4..b2f58c2e72 100644 --- a/tests/tools/dhcp-ubench/mysql_ubench.cc +++ b/tests/tools/dhcp-ubench/mysql_ubench.cc @@ -34,6 +34,15 @@ MySQL_uBenchmark::MySQL_uBenchmark(const string& hostname, const string& user, } +void MySQL_uBenchmark::stmt_failure(MYSQL_STMT * stmt, const char* operation) { + stringstream tmp; + tmp << "Error " << mysql_stmt_errno(stmt) << " during " << operation + << ": " << mysql_stmt_error(stmt); + throw tmp.str(); +} + + + void MySQL_uBenchmark::failure(const char* operation) { stringstream tmp; tmp << "Error " << mysql_errno(conn_) << " during " << operation @@ -408,6 +417,7 @@ void MySQL_uBenchmark::searchLease4Test() { // 4th parameter: Client-id response[3].buffer_type = MYSQL_TYPE_STRING; response[3].buffer = &client_id; + response[3].buffer_length = sizeof(client_id); // 5th parameter: valid-lifetime response[4].buffer_type = MYSQL_TYPE_LONG; @@ -444,11 +454,24 @@ void MySQL_uBenchmark::searchLease4Test() { } int num_rows = 0; - if (!mysql_stmt_fetch(stmt)) { + int result = mysql_stmt_fetch(stmt); + switch (result) { + case 0: { if (lease_addr != addr) { failure("Returned data is bogus!"); } num_rows++; + break; + } + case MYSQL_NO_DATA: + { + // that's ok. We randomized non-existing address + break; + + } + default: { + stmt_failure(stmt, "RETRIEVE (mysql_stmt_fetch())"); + } } // we could call mysql_stmt_fetch again to check that there are no diff --git a/tests/tools/dhcp-ubench/mysql_ubench.h b/tests/tools/dhcp-ubench/mysql_ubench.h index c9fcc7c39a..be12fd6fd1 100644 --- a/tests/tools/dhcp-ubench/mysql_ubench.h +++ b/tests/tools/dhcp-ubench/mysql_ubench.h @@ -80,8 +80,25 @@ protected: /// Compared to its base version in uBenchmark class, this one logs additional /// MySQL specific information using mysql_errno() and mysql_error() functions. /// The outcome is the same: exception is thrown. + /// + /// @param operation brief description of the operation that caused error + /// + /// @sa stmt_failure() void failure(const char* operation); + /// @brief Used to report compiled statement failures. + /// + /// Compared to its base version in uBenchmark class, this one logs additional + /// MySQL specific information using mysql_stmt_errno() and mysql_stmt_error() + /// functions that are used for compiled statements error reporting. + /// + /// @param stmt MySQL compiled statement structure + /// @param operation brief description of the operation that caused error + /// + /// @sa failure() + void stmt_failure(MYSQL_STMT * stmt, const char* operation); + + /// Handle to MySQL database connection. MYSQL* conn_; }; From 212745177be39f765b5e53c3697067780112fb4a Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Thu, 30 Aug 2012 13:51:59 +0200 Subject: [PATCH 058/148] [357] update doxygen and comments --- src/bin/auth/auth_config.cc | 1 + src/bin/auth/auth_srv.h | 7 +++++++ src/bin/auth/tests/config_unittest.cc | 1 + src/lib/asiodns/dns_server.h | 10 ++++++++++ src/lib/asiodns/dns_service.cc | 2 +- src/lib/asiodns/dns_service.h | 14 +++++++++++++- src/lib/asiodns/tcp_server.cc | 17 +++++++++-------- src/lib/asiodns/tests/dns_server_unittest.cc | 8 ++++++-- 8 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc index 987f1ee53e..6cc356e792 100644 --- a/src/bin/auth/auth_config.cc +++ b/src/bin/auth/auth_config.cc @@ -117,6 +117,7 @@ private: AddrListPtr rollbackAddresses_; }; +/// \brief Configuration for TCP receive timeouts class TCPRecvTimeoutConfig : public AuthConfigParser { public: TCPRecvTimeoutConfig(AuthSrv& server) : server_(server) diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h index e2d7d2f47b..e2ffd71526 100644 --- a/src/bin/auth/auth_srv.h +++ b/src/bin/auth/auth_srv.h @@ -320,6 +320,13 @@ public: std::vector getClientListClasses() const; /// \brief Sets the timeout for incoming TCP connections + /// + /// Incoming TCP connections that have not sent their data + /// withing this time are dropped. + /// + /// \param timeout The timeout (in milliseconds). If se to + /// zero, no timeouts are used, and the connection will remain + /// open forever. void setTCPRecvTimeout(size_t timeout); private: diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc index 8139d3359a..84f86b4fc2 100644 --- a/src/bin/auth/tests/config_unittest.cc +++ b/src/bin/auth/tests/config_unittest.cc @@ -143,6 +143,7 @@ TEST_F(AuthConfigTest, listenAddressConfig) { EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options); } +// Try setting tcp receive timeout through config TEST_F(AuthConfigTest, tcpRecvTimeoutConfig) { configureAuthServer(server, Element::fromJSON( "{ \"tcp_recv_timeout\": 123 }")); diff --git a/src/lib/asiodns/dns_server.h b/src/lib/asiodns/dns_server.h index 9f3bb6dd47..bc398056c4 100644 --- a/src/lib/asiodns/dns_server.h +++ b/src/lib/asiodns/dns_server.h @@ -99,6 +99,16 @@ public: virtual DNSServer* clone() { return (self_->clone()); } //@} + /// \brief Set timeout for incoming TCP connections + /// + /// Since this value is not relevant for every type of DNSServer + /// (like UDPServer), it has a no-op default implementation. + /// It is in the base class because the AuthSrv's DNSService has + /// no direct access to the derived API's after initialization, + /// and it does need to update running servers if the timeout + /// setting is changed. + /// + /// \param timeout The timeout in milliseconds virtual void setTCPRecvTimeout(size_t) {} protected: diff --git a/src/lib/asiodns/dns_service.cc b/src/lib/asiodns/dns_service.cc index 11c86b0fb1..03ec09dba7 100644 --- a/src/lib/asiodns/dns_service.cc +++ b/src/lib/asiodns/dns_service.cc @@ -40,7 +40,7 @@ public: DNSServiceImpl(IOService& io_service, SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) : io_service_(io_service), checkin_(checkin), lookup_(lookup), - answer_(answer) + answer_(answer), tcp_recv_timeout_(1000) {} IOService& io_service_; diff --git a/src/lib/asiodns/dns_service.h b/src/lib/asiodns/dns_service.h index e65354fefe..0b578fbd9b 100644 --- a/src/lib/asiodns/dns_service.h +++ b/src/lib/asiodns/dns_service.h @@ -84,7 +84,19 @@ public: ServerFlag options = SERVER_DEFAULT) = 0; virtual void clearServers() = 0; - /// Sets the timeout TODO + /// \brief Set the timeout for TCP DNS services + /// + /// The timeout is used for incoming TCP connections, so + /// that the connection is dropped if not all query data + /// is read. + /// + /// For existing DNSServer objects, where the timeout is + /// relevant (i.e. TCPServer instances), the timeout value + /// is updated. + /// The given value is also kept to use for DNSServer instances + /// which are created later + /// + /// \param timeout The timeout in milliseconds virtual void setTCPRecvTimeout(size_t timeout) = 0; virtual asiolink::IOService& getIOService() = 0; diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc index 616ca6720e..c291b6ff93 100644 --- a/src/lib/asiodns/tcp_server.cc +++ b/src/lib/asiodns/tcp_server.cc @@ -47,8 +47,6 @@ namespace asiodns { /// The following functions implement the \c TCPServer class. /// /// The constructor -// timeout is initialized to be sure, but it should be updated -// quite immediately anyway TCPServer::TCPServer(io_service& io_service, int fd, int af, const SimpleCallback* checkin, const DNSLookup* lookup, @@ -73,7 +71,7 @@ TCPServer::TCPServer(io_service& io_service, int fd, int af, isc_throw(IOError, exception.what()); } // Set it to some value. It should be set to the right one - // immediately, but set something non-zero just in case. + // immediately, but set it to something non-zero just in case. tcp_recv_timeout_.reset(new size_t(1000)); } @@ -133,11 +131,14 @@ TCPServer::operator()(asio::error_code ec, size_t length) { /// asynchronous read call. data_.reset(new char[MAX_LENGTH]); - timeout_.reset(new asio::deadline_timer(io_)); - timeout_->expires_from_now( - boost::posix_time::milliseconds(*tcp_recv_timeout_)); - timeout_->async_wait(boost::bind(&do_timeout, boost::ref(*socket_), - asio::placeholders::error)); + /// Start a timer to drop the connection if it is idle + if (*tcp_recv_timeout_ > 0) { + timeout_.reset(new asio::deadline_timer(io_)); + timeout_->expires_from_now( + boost::posix_time::milliseconds(*tcp_recv_timeout_)); + timeout_->async_wait(boost::bind(&do_timeout, boost::ref(*socket_), + asio::placeholders::error)); + } /// Read the message, in two parts. First, the message length: CORO_YIELD async_read(*socket_, asio::buffer(data_.get(), diff --git a/src/lib/asiodns/tests/dns_server_unittest.cc b/src/lib/asiodns/tests/dns_server_unittest.cc index 412dd59a9f..c05a34b1ad 100644 --- a/src/lib/asiodns/tests/dns_server_unittest.cc +++ b/src/lib/asiodns/tests/dns_server_unittest.cc @@ -281,10 +281,16 @@ class TCPClient : public SimpleClient { std::string(received_data_ + 2)); } + /// Set the delay before the data len is sent (in seconds) + /// If this is non-zero, the actual data is never sent + /// (it is used to test timeout, in which case the connection + /// should have been closed by the other side anyway) void setSendDataLenDelay(size_t send_data_len_delay) { send_data_len_delay_ = send_data_len_delay; } + /// Set the delay before the packet data itself is sent + /// (in seconds) void setSendDataDelay(size_t send_data_delay) { send_data_delay_ = send_data_delay; } @@ -328,8 +334,6 @@ class TCPClient : public SimpleClient { std::string data_to_send_; uint16_t data_to_send_len_; - // if 0, send body immediately - // if >0, send after the delay (in seconds) size_t send_data_delay_; size_t send_data_len_delay_; }; From 5298a0caf701c0d3a567679d1519de1f9fdb9a4a Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Thu, 30 Aug 2012 14:21:20 +0200 Subject: [PATCH 059/148] [357] update bind10-guide and auth manpage --- doc/guide/bind10-guide.xml | 10 ++++++++++ src/bin/auth/b10-auth.xml | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index 49cb419de6..61cddd6ff4 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -1633,6 +1633,16 @@ can use various data source backends. + + tcp_recv_timeout + + + tcp_recv_timeout is the timeout used on + incoming TCP connections, in milliseconds. If the query + is not sent within this time, the connection is closed. + + + diff --git a/src/bin/auth/b10-auth.xml b/src/bin/auth/b10-auth.xml index 37843e3de8..556873c86b 100644 --- a/src/bin/auth/b10-auth.xml +++ b/src/bin/auth/b10-auth.xml @@ -152,6 +152,12 @@ The default is 60. + + tcp_recv_timeout is the timeout used on + incoming TCP connections, in milliseconds. If the query + is not sent within this time, the connection is closed. + + The configuration commands are: From f2f058d5a3ee567c0be22f758a02abacc159e927 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Thu, 30 Aug 2012 15:43:44 +0200 Subject: [PATCH 060/148] [master] add missing LDADD to benchmark makefile --- src/lib/datasrc/memory/benchmarks/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/datasrc/memory/benchmarks/Makefile.am b/src/lib/datasrc/memory/benchmarks/Makefile.am index e86c1944eb..81d56422cf 100644 --- a/src/lib/datasrc/memory/benchmarks/Makefile.am +++ b/src/lib/datasrc/memory/benchmarks/Makefile.am @@ -14,4 +14,5 @@ noinst_PROGRAMS = rdata_reader_bench rdata_reader_bench_SOURCES = rdata_reader_bench.cc rdata_reader_bench_LDADD = $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la +rdata_reader_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la rdata_reader_bench_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la From ba9148b99d97cf140628989c3ff49127fc87931b Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Thu, 30 Aug 2012 17:19:28 +0200 Subject: [PATCH 061/148] [2143] DHCP Performance measurements - DHCP benchmarks run - DHCP Performance Guide updated with precompiled statement results --- tests/tools/dhcp-ubench/Makefile | 2 +- tests/tools/dhcp-ubench/dhcp-perf-guide.html | 142 ++++-- tests/tools/dhcp-ubench/dhcp-perf-guide.xml | 412 ++++++++++++++++-- .../performance-results-graph1.png | Bin 39126 -> 38873 bytes .../performance-results-graph2.png | Bin 0 -> 38979 bytes .../tools/dhcp-ubench/performance-results.ods | Bin 35877 -> 48268 bytes 6 files changed, 483 insertions(+), 73 deletions(-) create mode 100644 tests/tools/dhcp-ubench/performance-results-graph2.png diff --git a/tests/tools/dhcp-ubench/Makefile b/tests/tools/dhcp-ubench/Makefile index dbcfadd072..599c4f69a1 100644 --- a/tests/tools/dhcp-ubench/Makefile +++ b/tests/tools/dhcp-ubench/Makefile @@ -1,5 +1,5 @@ # Linux switches -CFLAGS=-g -Ofast -Wall -pedantic -Wextra +CFLAGS= -Ofast -Wall -pedantic -Wextra # Mac OS: We don't use pedantic as Mac OS version of MySQL (5.5.24) does use long long (not part of ISO C++) #CFLAGS=-g -O0 -Wall -Wextra -I/opt/local/include diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.html b/tests/tools/dhcp-ubench/dhcp-perf-guide.html index fd1929e901..0fc4a617bf 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.html +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.html @@ -1,11 +1,11 @@ -DHCP Performance Guide

DHCP Performance Guide

Tomasz Mrugalski

This is a companion document for BIND 10 version - 20120712.

Abstract

BIND 10 is a framework that features Domain Name System +DHCP Performance Guide

DHCP Performance Guide

Tomasz Mrugalski

This is a companion document for BIND 10 version + 20120817.

Abstract

BIND 10 is a framework that features Domain Name System (DNS) suite and Dynamic Host Configuration Protocol (DHCP) servers with development managed by Internet Systems Consortium (ISC). This document describes various aspects of DHCP performance, measurements and tuning. It covers BIND 10 DHCP (codename Kea), existing ISC DHCP4 software, perfdhcp (a DHCP performance - measurement tool) and other related topics.


Preface

Table of Contents

1. Acknowledgements

1. Acknowledgements

ISC would like to acknowledge generous support for + measurement tool) and other related topics.


Preface

Table of Contents

1. Acknowledgements

1. Acknowledgements

ISC would like to acknowledge generous support for BIND 10 development of DHCPv4 and DHCPv6 components provided by Comcast.

Chapter 1. Introduction

This document is in its early stages of development. It is @@ -15,9 +15,9 @@ tools.

Chapter 2. ISC DHCP 4.x

TODO: Write something about ISC DHCP4 here. -

Chapter 3. Kea

-

3.1. Backend performance evaluation

+

3.1. Backend performance evaluation

Kea will support several different database backends, using both popular databases (like MySQL or SQLite) and custom-developed solutions (like in-memory database). BIND 10 @@ -111,13 +111,20 @@ Possible command-line parameters: -c yes|no - should compiled statements be used (MySQL only)

-

3.2.1. MySQL tweaks

One parameter that has huge impact on performance is a a backend engine. +

3.2.1. MySQL tweaks

One parameter that has huge impact on performance is a a backend engine. You can get a list of engines of your MySQL implementation by using

> show engines;

- in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench will - use MyISAM for synchronous mode and InnoDB for asynchronous.

3.3. SQLite-ubench

SQLite backend requires both sqlite3 development and run-time package. Their + in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench uses + use MyISAM for synchronous mode and InnoDB for asynchronous. Please use + '-s 0|1' to choose whether you want synchronous or asynchronous operations.

Another parameter that affects performance are precompiled statements. + In a basic approach, the actual SQL query is passed as a text string that is + then parsed by the database engine. Alternative is a so called precompiled + statement. In this approach the SQL query is compiled an specific values are being + bound to it. In the next iteration the query remains the same, only bound values + are changing (e.g. searching for a different address). Usage of basic or precompiled + statements is controlled with '-c 0|1'.

3.3. SQLite-ubench

SQLite backend requires both sqlite3 development and run-time package. Their names may vary from system to system, but on Ubuntu 12.04 they are called sqlite3 libsqlite3-dev. To install them, use the following command: @@ -136,14 +143,16 @@ Possible command-line parameters: switches can be used. Currently supported parameters are (default values specified in brackets):

  1. -f filename - name of the database file ("sqlite.db")

  2. -n num - number of iterations (100)

  3. -s yes|no - should the operations be performend in synchronous (yes) - or asynchronous (no) manner (yes)

  4. -v yes|no - verbose mode. Should the test print out progress? (yes)

  5. -c yes|no - compiled statements. Should the SQL statements be precompiled?

+ or asynchronous (no) manner (yes)

  • -v yes|no - verbose mode. Should the test print out progress? (yes)

  • -c yes|no - precompiled statements. Should the SQL statements be precompiled?

  • SQLite can run in asynchronous or synchronous mode. This mode can be controlled by using sync parameter. It is set using (PRAGMA synchronous = ON or OFF).

    Another tweakable feature is journal mode. It can be turned to several modes of operation. Its value can be modified in SQLite_uBenchmark::connect(). See http://www.sqlite.org/pragma.html#pragma_journal_mode for - detailed explanantion.

    3.4. memfile-ubench

    Memfile backend is custom developed prototype backend that + detailed explanantion.

    sqlite_bench supports precompiled statements. Please use + '-c 0|1' to define which should be used: basic SQL query (0) or + precompiled statement (1).

    3.4. memfile-ubench

    Memfile backend is custom developed prototype backend that somewhat mimics operation of ISC DHCP4. It uses in-memory storage using standard C++ and boost mechanisms (std::map and boost::shared_ptr<>). All database changes are also @@ -157,39 +166,116 @@ Possible command-line parameters:

    memfile can run in asynchronous or synchronous mode. This mode can be controlled by using sync parameter. It uses fflush() and fsync() in synchronous mode to make sure that - data is not buffered and physically stored on disk.

    3.5. Performance measurements

    This section contains sample results for backend performance measurements, + data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    -HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm (used only one of them), ext4 partition
    +HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition
     OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
     compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
     MySQL version: 5.5.24
     SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e

    -

    Benchmarks were run in two series: synchronous and +

    Benchmarks were run without using precompiled statements. + The code was compiled wit -O0 flag (no code optimizations). + Each run was executed once.

    Benchmarks were run in two series: synchronous and asynchronous. As those modes offer radically different performances, synchronous mode was conducted for 1000 (one thousand) repetitions and asynchronous mode was conducted for - 100000 (hundred thousand) repetitions.

    Table 3.1. Synchronous results

    BackendOperationsCreateSearchUpdateDeleteAverage
    MySQL100031.603978s 0.116612s27.964191s27.695209s21.844998s
    SQLite100061.421356s 0.033283s59.476638s56.034150s44.241357s
    memfile100041.711886s 0.000724s42.267578s42.169679s31.537467s

    Following parameters were measured for asynchronous mode. + 100000 (hundred thousand) repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreateSearchUpdateDeleteAverage
    MySQL100031.603978s 0.116612s27.964191s27.695209s21.844998s
    SQLite100061.421356s 0.033283s59.476638s56.034150s44.241357s
    memfile100038.223757s 0.000817s38.041153s38.017293s28.570755s

    Following parameters were measured for asynchronous mode. MySQL and SQLite were run with 100 thousand repetitions. Memfile - was run for 1 million repetitions due to much larger performance.

    Table 3.2. Asynchronous results

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL10000010.584842s10.386402s10.062384s 8.890197s 9.980956s
    SQLite100000 3.710356s 3.159129s 2.865354s 2.439406s 3.043561s
    memfile1000000 (sic!) 6.084131s 0.862667s 6.018585s 5.146704s 4.528022s

    Presented performance results can be computed into operations per second metrics. + was run for 1 million repetitions due to much larger performance.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL10000010.584842s10.386402s10.062384s 8.890197s 9.980956s
    SQLite100000 3.710356s 3.159129s 2.865354s 2.439406s 3.043561s
    memfile100000 1.299642s 0.039330s 1.307112s 1.277641s 0.980931s

    Presented performance results can be computed into operations per second metrics. It should be noted that due to large differences between various operations (sometime over 3 orders of magnitude), it is difficult to create a simple, readable chart with - that data.

    Table 3.3. Estimated performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)164362.011159195.84166152.01194299.11421002.24
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)23.971381215.4723.6623.71345321.70

    Performance measurements

    Graphical representation of the performance results - presented in table Table 3.3, “Estimated performance”.

    3.6. Possible further optimizations

    - For debugging purposes the code was compiled with -g -O0 - flags. While majority of the time was spent in backend - functions (that was probably compiled with -O2 flags), the - benchmark code could perform faster, when compiled with -O2, - rather than -O0. That is expected to affect memfile benchmark. + that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Basic performance measurements

    Graphical representation of the basic performance results + presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, + taken using microbenchmarks. Tests were conducted on reasonably powerful machine: +

    +CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    +HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition
    +OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
    +compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
    +MySQL version: 5.5.24
    +SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e

    +

    Benchmarks were run with precompiled statements enabled. + The code was compiled wit -Ofast flag (optimize compilation for speed). + Each run was repeated 3 times and measured values were averaged.

    Benchmarks were run in two series: synchronous and + asynchronous. As those modes offer radically different + performances, synchronous mode was conducted for 1000 (one + thousand) repetitions and asynchronous mode was conducted for + 100000 (hundred thousand) repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreateSearchUpdateDeleteAverage
    MySQL100027.887s 0.106s28.223s27.696s20.978s
    SQLite100061.299s 0.015s59.648s61.098s45.626s
    memfile100039.564s 0.000724s39.543s39.326w29.608s

    Following parameters were measured for asynchronous mode. + MySQL and SQLite were run with 100 thousand repetitions. Memfile + was run for 1 million repetitions due to much larger performance.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1000008.507s9.698s7.785s8.326s8.579s
    SQLite100000 1.562s 0.949s 1.513s 1.502s 1.382s
    memfile1000001.302s0.038s1.306s1.263s0.977s

    Presented performance results can be computed into operations per second metrics. + It should be noted that due to large differences between various operations (sometime + over 3 orders of magnitude), it is difficult to create a simple, readable chart with + that data.

    Table 3.6. Estimated optimized performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)11754.8410311.3412845.3512010.2411730.44
    SQLite (async)64005.90105391.2966075.5166566.4375509.78
    memfile (async)76832.162636018.5676542.5079188.81717145.51
    MySQL (sync)35.869461.1035.4336.112392.12
    SQLite (sync)16.3167036.1116.7616.3716771.39
    memfile (sync)25.283460207.6125.2925.43865070.90

    Optimized performance measurements

    Graphical representation of the optimized performance + results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    + Improvements gained by introducing support for precompiled + statements in MySQL is somewhat disappointing - between 6 and + 29%. On the other hand, the improvement in SQLite is + surprisingly high - the efficiency is more than doubled.

    - Currently all operations were conducted on one by one - basis. Each operation was treated as a separate + Compiled statements do not have any measureable impact on + synchronous operations. That is as expected, because the major + bottleneck is the disk performance. +

    + Compilation flags yield surprisingly high improvements for C++ + STL code. The memfile backend is in some operations is almost + twice as fast. +

    + If synchronous operation is required the current performance + results are likely to be deemed inadequate. The limiting + factor here is a disk access time. Even migrating to high + performance 15.000rpm disk is expected to only roughly double + number of leases per second, compared to the current results. + The reason is that to write a file to disk, at lease 2 writes + are required: the new content and i-node modification of the + file. The easiest way to boost synchronous performance is to + switch to SSD disks. Memory-backed RAM disks are also viable + solution. However, care should be taken to properly engineer + backup strategy for RAM disks. +

    + While the custom made backend (memfile) provides the best + perfomance, it carries over all the limitations existing in + the ISC DHCP4 code: there are no external tools to query or + change database, the maintenance requires deep knowledge etc. + Those flaws are not shared by usage of a proper database + backend, like MySQL and SQLite. They both offer third party + tools for administrative tasks, they are well documented and + maintained. However, SQLite support for concurrent access is + limiting in certain cases. Since all three investigated + backends more than meet expected performance results, it is + recommended to use MySQL as a first concrete database backend. + Should this choice be rejected for any reason, the second + recommended choice is SQLite. +

    + It should be emphaisized that obtained measurements indicate + only database performance and they cannot be directly + translated to expected leases per second or queries per second + performance by an actual server. The DHCP server must do much + more than just query the database to properly process client's + message. Provided results should be considered as only rough + estimates. They can also be used for relative comparisons + between backends. +

    3.8. Possible further optimizations

    + For basic measurements the code was compiled with -g -O0 + flags. For optimized measurements the benchmarking code was + compiled with -Ofast (optimize for speed). In both cases, the + same backend (MySQL or SQLite) library was used. It may be + useful to recompile the libraries (or the whole server in case + of MySQL) with -Ofast. +

    + There are many MySQL parameters that various sources recommend + to improve performance. They were not investigated further. +

    + Currently all operations are conducted on one by one + basis. Each operation is treated as a separate transaction. Grouping X operations together will potentially - bring almost X fold increase in synchronous operations. - Extension for this benchmark in this regard should be considered. - That affects only write operations (insert, update and delete). Read - operations (search) are expected to be barely affected. + bring almost X fold increase in synchronous operations. Such a + feature is present in ISC DHCP4 and is called cache-threshold. + Extension for this benchmark in this regard should be + considered. That affects only write operations (insert, + update and delete). Read operations (search) are expected to + be barely affected.

    Multi-threaded or multi-process benchmark may be considered in the future. It may be somewhat difficult as only some backends diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml index 16bbd63fa9..1ddd79b4c1 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml @@ -239,8 +239,17 @@ Possible command-line parameters: > show engines; - in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench will - use MyISAM for synchronous mode and InnoDB for asynchronous. + in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench uses + use MyISAM for synchronous mode and InnoDB for asynchronous. Please use + '-s 0|1' to choose whether you want synchronous or asynchronous operations. + + Another parameter that affects performance are precompiled statements. + In a basic approach, the actual SQL query is passed as a text string that is + then parsed by the database engine. Alternative is a so called precompiled + statement. In this approach the SQL query is compiled an specific values are being + bound to it. In the next iteration the query remains the same, only bound values + are changing (e.g. searching for a different address). Usage of basic or precompiled + statements is controlled with '-c 0|1'. @@ -277,7 +286,7 @@ Possible command-line parameters: -s yes|no - should the operations be performend in synchronous (yes) or asynchronous (no) manner (yes) -v yes|no - verbose mode. Should the test print out progress? (yes) - -c yes|no - compiled statements. Should the SQL statements be precompiled? + -c yes|no - precompiled statements. Should the SQL statements be precompiled? @@ -290,6 +299,10 @@ Possible command-line parameters: modified in SQLite_uBenchmark::connect(). See http://www.sqlite.org/pragma.html#pragma_journal_mode for detailed explanantion. + + sqlite_bench supports precompiled statements. Please use + '-c 0|1' to define which should be used: basic SQL query (0) or + precompiled statement (1). @@ -325,18 +338,22 @@ Possible command-line parameters:

    - Performance measurements + Basic performance measurements This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine: CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores) -HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm (used only one of them), ext4 partition +HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64 compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 MySQL version: 5.5.24 SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e + Benchmarks were run without using precompiled statements. + The code was compiled wit -O0 flag (no code optimizations). + Each run was executed once. + Benchmarks were run in two series: synchronous and asynchronous. As those modes offer radically different performances, synchronous mode was conducted for 1000 (one @@ -344,7 +361,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 100000 (hundred thousand) repetitions. - Synchronous results +
    Synchronous results (basic) @@ -388,11 +405,11 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile 1000 - 41.711886s - 0.000724s - 42.267578s - 42.169679s - 31.537467s + 38.223757s + 0.000817s + 38.041153s + 38.017293s + 28.570755s @@ -404,7 +421,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 was run for 1 million repetitions due to much larger performance. -
    Asynchronous results +
    Asynchronous results (basic) @@ -447,12 +464,12 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile - 1000000 (sic!) - 6.084131s - 0.862667s - 6.018585s - 5.146704s - 4.528022s + 100000 + 1.299642s + 0.039330s + 1.307112s + 1.277641s + 0.980931s @@ -464,7 +481,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 over 3 orders of magnitude), it is difficult to create a simple, readable chart with that data. -
    Estimated performance +
    Estimated basic performance @@ -503,11 +520,11 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile (async) - 164362.01 - 1159195.84 - 166152.01 - 194299.11 - 421002.24 + 76944.27 + 2542588.35 + 76504.54 + 78269.25 + 693576.60 @@ -531,11 +548,11 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile (sync) - 23.97 - 1381215.47 - 23.66 - 23.71 - 345321.70 + 26.16 + 1223990.21 + 26.29 + 26.30 + 306017.24 @@ -547,33 +564,340 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 - Performance measurements + Basic performance measurements
    - Possible further optimizations + Optimized performance measurements + This section contains sample results for backend performance measurements, + taken using microbenchmarks. Tests were conducted on reasonably powerful machine: + +CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores) +HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition +OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64 +compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 +MySQL version: 5.5.24 +SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e + + + Benchmarks were run with precompiled statements enabled. + The code was compiled wit -Ofast flag (optimize compilation for speed). + Each run was repeated 3 times and measured values were averaged. + + Benchmarks were run in two series: synchronous and + asynchronous. As those modes offer radically different + performances, synchronous mode was conducted for 1000 (one + thousand) repetitions and asynchronous mode was conducted for + 100000 (hundred thousand) repetitions. + + +
    - Graphical representation of the performance results - presented in table . + Graphical representation of the basic performance results + presented in table .
    Synchronous results (optimized) + + + + + + + + + + + Backend + Operations + Create + Search + Update + Delete + Average + + + + + MySQL + 1000 + 27.887s + 0.106s + 28.223s + 27.696s + 20.978s + + + + SQLite + 1000 + 61.299s + 0.015s + 59.648s + 61.098s + 45.626s + + + + memfile + 1000 + 39.564s + 0.000724s + 39.543s + 39.326w + 29.608s + + + + +
    + + Following parameters were measured for asynchronous mode. + MySQL and SQLite were run with 100 thousand repetitions. Memfile + was run for 1 million repetitions due to much larger performance. + + + Asynchronous results (optimized) + + + + + + + + + + + Backend + Operations + Create [s] + Search [s] + Update [s] + Delete [s] + Average [s] + + + + + MySQL + 100000 + 8.507s + 9.698s + 7.785s + 8.326s + 8.579s + + + + SQLite + 100000 + 1.562s + 0.949s + 1.513s + 1.502s + 1.382s + + + + memfile + 100000 + 1.302s + 0.038s + 1.306s + 1.263s + 0.977s + + + + +
    + + Presented performance results can be computed into operations per second metrics. + It should be noted that due to large differences between various operations (sometime + over 3 orders of magnitude), it is difficult to create a simple, readable chart with + that data. + + Estimated optimized performance + + + + + + + + + + Backend + Create [oper/s] + Search [oper/s] + Update [oper/s] + Delete [oper/s] + Average [oper/s] + + + + + MySQL (async) + 11754.84 + 10311.34 + 12845.35 + 12010.24 + 11730.44 + + + + SQLite (async) + 64005.90 + 105391.29 + 66075.51 + 66566.43 + 75509.78 + + + + memfile (async) + 76832.16 + 2636018.56 + 76542.50 + 79188.81 + 717145.51 + + + + + MySQL (sync) + 35.86 + 9461.10 + 35.43 + 36.11 + 2392.12 + + + + SQLite (sync) + 16.31 + 67036.11 + 16.76 + 16.37 + 16771.39 + + + + memfile (sync) + 25.28 + 3460207.61 + 25.29 + 25.43 + 865070.90 + + + + +
    + + + + + + + Optimized performance measurements + + + Graphical representation of the optimized performance + results presented in table . + + + +
    + +
    + Conclusions - For debugging purposes the code was compiled with -g -O0 - flags. While majority of the time was spent in backend - functions (that was probably compiled with -O2 flags), the - benchmark code could perform faster, when compiled with -O2, - rather than -O0. That is expected to affect memfile benchmark. + Improvements gained by introducing support for precompiled + statements in MySQL is somewhat disappointing - between 6 and + 29%. On the other hand, the improvement in SQLite is + surprisingly high - the efficiency is more than doubled. - Currently all operations were conducted on one by one - basis. Each operation was treated as a separate + Compiled statements do not have any measureable impact on + synchronous operations. That is as expected, because the major + bottleneck is the disk performance. + + + Compilation flags yield surprisingly high improvements for C++ + STL code. The memfile backend is in some operations is almost + twice as fast. + + + + If synchronous operation is required the current performance + results are likely to be deemed inadequate. The limiting + factor here is a disk access time. Even migrating to high + performance 15.000rpm disk is expected to only roughly double + number of leases per second, compared to the current results. + The reason is that to write a file to disk, at lease 2 writes + are required: the new content and i-node modification of the + file. The easiest way to boost synchronous performance is to + switch to SSD disks. Memory-backed RAM disks are also viable + solution. However, care should be taken to properly engineer + backup strategy for RAM disks. + + + + While the custom made backend (memfile) provides the best + perfomance, it carries over all the limitations existing in + the ISC DHCP4 code: there are no external tools to query or + change database, the maintenance requires deep knowledge etc. + Those flaws are not shared by usage of a proper database + backend, like MySQL and SQLite. They both offer third party + tools for administrative tasks, they are well documented and + maintained. However, SQLite support for concurrent access is + limiting in certain cases. Since all three investigated + backends more than meet expected performance results, it is + recommended to use MySQL as a first concrete database backend. + Should this choice be rejected for any reason, the second + recommended choice is SQLite. + + + + It should be emphaisized that obtained measurements indicate + only database performance and they cannot be directly + translated to expected leases per second or queries per second + performance by an actual server. The DHCP server must do much + more than just query the database to properly process client's + message. Provided results should be considered as only rough + estimates. They can also be used for relative comparisons + between backends. + + +
    + +
    + Possible further optimizations + + For basic measurements the code was compiled with -g -O0 + flags. For optimized measurements the benchmarking code was + compiled with -Ofast (optimize for speed). In both cases, the + same backend (MySQL or SQLite) library was used. It may be + useful to recompile the libraries (or the whole server in case + of MySQL) with -Ofast. + + + There are many MySQL parameters that various sources recommend + to improve performance. They were not investigated further. + + + Currently all operations are conducted on one by one + basis. Each operation is treated as a separate transaction. Grouping X operations together will potentially - bring almost X fold increase in synchronous operations. - Extension for this benchmark in this regard should be considered. - That affects only write operations (insert, update and delete). Read - operations (search) are expected to be barely affected. + bring almost X fold increase in synchronous operations. Such a + feature is present in ISC DHCP4 and is called cache-threshold. + Extension for this benchmark in this regard should be + considered. That affects only write operations (insert, + update and delete). Read operations (search) are expected to + be barely affected. Multi-threaded or multi-process benchmark may be considered in diff --git a/tests/tools/dhcp-ubench/performance-results-graph1.png b/tests/tools/dhcp-ubench/performance-results-graph1.png index 290816f16b1dfc436043de630ee8a981338e193e..a173aa6a832746f149ed71752adb6aff4152043b 100644 GIT binary patch literal 38873 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

    |a5))xXKQzwN&_-TwnyF9Z(!%^dz46#V`C7aE8b zLFE)&K4B6E_86uqKb+LPQ8yInSEs!yc3kfu7P|D4Xzxti@hP4!?5N2QP=xe%&klcU z2FuyM)=Plb*0qw(U8L#X*B;ms1`EI1gS>5MJR`jr)xIUr7YLGGoyMETteV&C-`Xh} zPk_uNpbfesw1hIu^*R9&E_*Jcyz7vEmeauG!>q`og_a`{hsy!ahMa=c6Md}cHQV-4 zs>ohDz`ZiAswxJOHdLw(2SvSPM(;7pe}q#4zHaC}LUMeFjduEV?NG`{*~QgNoQ zY9PyyF3PUDfXajBw}&SABk;C!1=MSnJg1@ZSoPrL7r+`Lcwlxv%kDq1#yqdxd^P)$(%iAz z5`yn};f|_U4nH~*+mS8x0tp*eoY;d&zLU+^@P_JpQ^U02IvMFt>xS`k#LST!sqRAt zf;=HE*DYzzidFp7QVvzddZ6Dw+=nV1?^`}!C9ckRL(Wi{-h4~-@{W!52g?Q!W6{&e zPRlx75N%$|XM^B)!AF|bB}YB_IlM1Pa_b|8lF)~ug5t{Isb&*T+^)pR4E@o0P=aVg zz~!Gbi#?G`fW`kF%Nipaz5b^b;7?lqA6yHW$p8M~`WO2C`*d3~A}_y&Tvqn>`CWhA z+)Zyut-V@dlI9D>ZV2*k6kL*s`&Z)DhNBH0lKkiPuXp{{u;B6MrxIy8e?;81sqY%} zZ@x|lEu}+Vqm_(U;TR}B+h6_wZ(X^7@06VLZb2?)=?%5xCmxt*Ixu zFDdDyRkqQWH2mZ@y;pxBi6E`w@$1zIC`fc&ycV+d`@WjeT~re^fH3q5RbY^>ouHH@FnXaE1n(Y0dL`w;fU5$x2O zQ6Q*wE&b}}f5K$>=HD>+BlNKIr1SQ3w!BmONox{ZQAzgJmWcpw4LDLF9|Eg*ygIpl z`Fk0qxK61~=3VNO2pB(Pq_LYyEFETu27>o)^p7ry+1>s397+KIEF?kh$|vi^n!<@> z3HM|55YV@?Ap2|A`~oxSeBEO4NZfeHYtGdqAK}b9s|C>RCV*_4tB)I}HCDdJu7k<~ ziE+D2NtJ>N!t*48) ze|I$Jg3IK)5(^Ksb5>&=vpf1)YRQDJc8(F-mcPf8tgPrkf->(yAd%~_zYx1TIaOu{ ze$9ofjdQ*Y=<)G$-CRnHsiQKETt>}FfX5r$hA+RSiDm_GaB!4$bXt`A4X}~U;+lVA z9+P&&`DUk%MAII3Ma-XWpWn6f*+U9OTBSQ76(immJmc_M)Fqqh)Eha5#q?dvnScN@ zLh&G4U%ashR9~MY0fwkZ-$&= z?B)^5zOimBI9S{8C8<9Fhdbs>L~t@`GhDCq`|f}eERgoX3Wq75NLvUKI3~DxutHeQ z9rQ=`sJk*hSL2X*KC^t}nMhACVP0Sqibf7b{QOS5^zF}W<}}PqNme4;S}*h$Eo6#p zWJQhH_cito+|Yp(_d_KT5Q_hk%ThwO3(?Svd{WRy)_46$&OpI}omsn!sm6;v?L9LT z^d1dzngX@G-FGfO^_TsFN0(bn%slh$`lo5FZvIW`HbP+c#ycEwGd50~?S(U5w}#w5 z_On4zsY4pu4F4@;BLzT2iAV(HnDNMdb$0j>wf2b$n#iWs8~LS-V~XmXHba7T37PaO zwYYB05~iZUn$&D0?AlLLJ&Z5AmyE2JC%*I_JtrL{EZ&Z8?ZZo{0+$p1V5qIN^pwvp zRqeJEo4)=*gu>Sdn8otn06DP3zX_xk-vKVOW`9cIR{P)&3I}t4d@C^pxlvt%pxwcS zM{eRT8ai)YZAis0de7&#d`I%ys1jQDdjIjO?$QXV@yT7qlEiKb$*_!uZ>CVsvS zvZ2yTN*SXN1E>`fdZ3z}t5IaEen{eaSZl*j#jZ&0Lt0u?0@Nj=7%1#ak_%;Z`gvkf zbvXjE_?RaFrk{})#v~yAKb4Gd)*p&@ZtdqABh_n7`kgxG4Sf%jjQNjL7ll}++yqo= zXfp%<89@*d-Qu?k?YHhk|ANpX8h-LyTWc*$8q zXe=#$@lj+kgmXKDm{40zl1LUX2gnou<}n-CzsRp;lTZ-H{Vh0xXK>?0cEFPN1L7x<6hTVq2dP%M!eXoE!PW2NdMs9oUOin`5 z;vA$VI2OHM?WeogD`kr&Z0u-KwK}NYDAZe)!}QID@wGSbQ%ZqA1#yVQgh2j8-R{pB z6F7L;1s3H2VqysuKu2^Ea*6p_>5b`^SG$?GEJZ?VX^hyM&CVH3cEn_5uA&Oy+9~;h$ZVX;V;75w4dfEWdq(#X}Ncj&;Wn;LApUyyQWJ;3bv?(nrr22dct_tM1# zXfJL8Ng?*e#OjQZ1g(k;{VQCulRe)E>^a4rN{76?Gnr18hwo$N$@MLN9HhV`pIm~M ztxHxVOC#n3NXd-AvDhUwM}|#EYbg8E>-SiCB-%1z@1}CtsjZ_y7RF9Iv63>ksrcHq zBi6WjT?115tkj%V^J=`TOWDCO!kLdNS6O#3U-Bm5v~eK8a@Mm0P0hvVn@dHBvjD6e zk#wo7#5X{DhiC{M7Bd|Zi;2{CM8i*tYHT;dX^9O$>5OXvyU|$aKVf!?tS4+x54Va_ zH~|m)uC6e-=3Ufk@NS(AB#pGo2H>PsFz?$iWH(zM+p#OmF-H9prGx3772M41kdR(+ z?*#A)59sxb$m5>l;M6&kLX&8qQF^arGkF~-RQj~?hN1i(2MacmmwgIu`?J4VD|Ls& zr@2LYnz@xmarPkpCX#|~*2A>zN82QLWSE#S44mf+jfXtCD#A7@%E_=Mb>v--X3(a9 zMW*7=oKP7)E)3e4H@u}DJkKN`k>&^V9ZTIi5e4bxWU?d_+bbxu`KlS zB1i(v+o9v$z~G_uvsH#LAGl{2zr#|5+g*W`tZB_0iCFl9ihr>sF0CND&|0Rs+F6;> z=Y8zOI%JKBP~51mIBe`f!J<{?dBrsOn5+Ht*1CxWvQB6>u<6c$ZH&cKWdl;(Xv0W=amR&IAf02Ofl9e(3-ePdlyJjxR03neHdVld&r&qa zXv4aFu+%cY%(AWbOR4|u=#RBGW;;{%U1^yU_o^g;$Hsm0?Ea8^oEjtt1YrdmmPrLZ zSS*|>+{74BlRQmPSupC4OsQJ#ts~4 z&DzPIMjk}9Yxo?SA}QL{eiOA7&t7#t*h5HoShtAq%I}N9&(podFxLIw+09qwO8*P% z_^Mr{P~etzV2mr5HC`i-f(S_v_So;acK{l`@MXaev}K{ho57}p>{o*bi^m)RA%4<0 z6&bf04kz=UWS4Nw&s->C(KZi+FtUG=egHL52?bAXGOQ`o?UWU@XmcB$_k5?l{m!MZ zNE_=qY}j{p5W%EVPfw-75#R675mGG5>KMmL7rjC9LUJ_GXw;M)o2j^W>kIN0Kf;tj zSPncnVmYVqhqjvZQb_6#qpJK@BxHlCipb4n2<>nEVQPje3D@y7lrtz+eRAu|Fcx=a z*J4Mh+gg9Romj_=^q(!BFS@{rK(Egu`~xoZGWYIiBa44oE$Eyt{+} zKCc7uxtCv7r;x|-0^IV@C+kwn)0O5r#|`)OI4dq0V`Jl`!{r5g+wVLJ;7HcrX?^#E zs_W2o_RBoXSLIsOpPl&Hl$RUbW82@@2mcZx7$m!HHy+vVYcJi-Ss$q6OLB($Yq-~nyXkAaX!ajv?1i{>g)WZ>PN~X2T%T+r6MC%je)~(* z3R#`(dmFf|o-0zJ9Vfpn&&U1M!!9l^zL%CRZCrE5n6g5!a@c%=_YV9JAD@;OuCoV9 zGC*$k>?1`&PKeC!mOiX3LC?^^=*IaKXkEQYohW$k@GVe`8ox5yKCid2@_E-Aa=~NIQNV zk0|U^)$8K@Ll)QiinnN}T*D|AL>~=Ly-he|Z5ipo^Zr62op}9OZX8dCsUk0u93+Ok z_ic28;KM6~{|=6@cEyb{hVPBk=TccG>D-6xxwv}?j7y5{77o~5qjn7$vRHx|2i(SN zBgB9Kj7u>cPk}OH^N#0pBfEZ2kJx@{$)6YW`c|C@ct!Mk6ybo1M{rF-Yjp-Y|1aua z&=u3Pz>YIb35m8)0tzP|M|3TWG@wKeOadHfKIgj$(JViYIHUP)0hjL>SPl+TkE;8LkX_Rf4}OJB+Xk7qoZD_xq!d$AS1h zZakbfzd=6I8Ncu9NK^3 zkSQdEr>!g`2KEg9?hAU~dU5siObPsvdu%wrtQG8CcLjlArMhGvPCdtQcczc|Sd_Hm?HcX6e<6*|xivYM7}o0Ydvmc(_}Ui9 z_vBrG9hTziIhtYSy`;kLRlCR>K?sPd%bwom5k!)=Bf-wTi%ae|>?6IQ+jy8?!e+|2 zWb+hy5b*UR{Rl6a7Z2%rw%Jw0F@~{d-db}~^qPs11RN?n)*RKnY>r7LeISYMx-9!_ z4vvAb?hL_hz|*8EQ7Dtly}QO7ca+Q}pG?9Ww3>b!LSxXka@cTOJ-xK~mh2-q#&?RR zA&4W#{y%ef+0($8^lim`bG;JD!n`zH=08_z>=n!fyi;9L8!hDO*wy?6A=K_mp^~}b zxHbA~LTg@)sY5$DAb|Rt&L_fJ*B0g9v!2q~yqd`SlLDsfIsU5B47KpI-~a^uyt2JQ z6Q=v$Z}-eSsn&U`Wu_o}i;XX%pOV^7E~=b+j|-W_$gChU1wc?|82x6KYQ0z#v|@!|lEh?K7q=UKiXzm`DlXE`FbLYSiN7Xx(h`)2A{5^r9y11h{+u*z z>gw&jv)ZPzlKG@4TK#^l%s42ez{l)0!(v&?!Q?xBu@AfQZe_2`-1y?AtJZ?OIW3ji zoCt90r9V#+Uo5*Bhn*||Y`sz-W@jcxx+Wa^H3}Z~brc={4NxiF!WcwRB{&%U5gGc! zb6H@`&K@FM7XoYPQapqMKD3hXgizUQMMPMSvtIzQ5j~C+l&uJAJG9=NDhR4-2_~?6 zK1SE9XLXOanmL?fIQ|j#d8j(#cyls76sxjqf5~!1jLWl`1Fc;7kw`v)KgOi-MRW>1 z@%WF4rfTTkYRZwCB)!NoR2n_=yUYix%$~D2*HGFgo&~d0gClgvN=?fFb&MH`b%U@;J(6Dvm!bW1&)Mf$w}r zB6v;5N1$erEmW|^Xj`GP$zRlnSmn}WK-x5&eLME*1r}4*HH%|_+DL>F^zumusjtI2 zagJ$H02NlG_WfX(TGi8O*aFjD8)r;;TSM=~veJaFCkN4CuTnzyKqsUQb{N-rA=6Kx zoi)-zQ1fECft~@+!u6z{pV(uMf@Oifxf>%VQ?qO9yje+2p6X4Jg~J!4ei;=`Wcr+i z%oQ-Q^&CSpW=S(DJTXXBqyuQd^6cmv(Nj30jc*xdI%XO+#7n?`A&eB;5fq~gAw~Ao z%`5mv0}ofp^!qgfcK2M(_GRW{Wsn*bFTUHh)4J4qj7A~$6pz-Ej~Pnr+d%JxSh(l- z=^K0NuPFg|p z4%^1NNP*e%d+>=^mt)weD+ciuS<)}hrdVKOGJsR$FT0v|JoWBSshfWUQ3GkMM2ryq zw0pNaF9t+v63^gR_u(P6R$n43kAGU`;M8(u|Jq#j%(Yy$dsWS((B`J7gKNe!@O1DJ z%~WAK5tA;o+kze^^g`jV+@lyUifvU_>Xsb6wzG851a3aS)fx0Kq6hx;pw%C-7PXcL zdc*x7GF}neHpc6Vl5aaB{C;Uq+_!dH{3h;UrrxjKM6@NxiBKF?`FmRL&JmCbc-c8! zVa3?K$V^~lP0_t3tQqDRlq{(6V^y`8DWdih6lqbBfP%v0VGiDBSoJT%ppp^>>f&J} z3er8y*c7a_RFFP{#Nw7q`bmvwYsLN5MIo=ovyZk`+#=cNmRLDJ?M6F2x%+N~u(E)U zAlLLqRL9X{S;04Y2OSOx^-_Y9i=S~3s$$434dZvGx#dxF%gS+D3hGns@9wJ+%zz*F z6G(T8eXET2vO0~2o;#?rmzMTRF`ggDWCDiC90Lhyu2&EE-<|jB6`9XY`G}?Di6Q1q z((Q8Q7ieT{W4XGNNcSO%lQjz^d}LE_%Evk%GGujZx>4`Y!Zba2KzAB$-=?pO#;Rbp zcogP!0WQl*alM=Ng5;VG5zp;|UHJr)6rCB~&A+o*UMRQH^>7f5b*>6fn9uk4rU-;m z?BI=Thd+I%@GWAi(a_W(Qlu`X30_LH@=cETsUqv1<#PMzNI&aF7P>EHRN=rf;SpB2 z^GJ{kjok2NGpksl9P`GNFy1++907gBpf}i%7T@n$rNxe|YaZ}Wi&P4pjk!~`MGX7U zn+!j&U@JmUKdQySk}^R83b&J^aQN710FjtWz??i`A-E2@8E@>mvpey7$~&L3%4ix2 zY{TS+ETVSCfn3G>g^6&!PM6xE`CUXCg`|Z>;10LvRfRgAZJwg!dRoFYBwo8O+n0iV z{7-1`D$vO(Ul8_RQ7wQb3Xd1-)3YvAiLQDIj2^HeLX%X51%p3QNH^(Ir`<_QQ4NX~ zWjdWofLEFh=ZCWnpRO+2;qIk02m15<;Ifl-aEl#Du0Y;vC)OCZ>Vgn zpD(pPsjqLW0GDg%-q=($CeKy;ijdWZUUW889H4_Ts=DR(<8ac9b}LcJ=gSk)I82Gb>}rvR_cjbw^eN} zZsVp0BfffCU8ScXdmR7yC}26?(wLr2iolPXSQE{xy3VPvgh{qT_S#9AxZ5N=H`w~KDzeaoj< zNuyQsVEv1b@Z0IAoeB(*b3uHBefM_L?>&yOg_ih>6Zg7HqAw=nT`7h=6E#?$V@|zw z$^TBzhe-YW6%9H%@wc&7)WF4$NCsLm8PHNec(3G$!ew~-z@{1Qg7NYOT#YdYv(C8v z)mMG<8p7341rGTX$tKrQ+d-pBRv#0m0==w`zh~9FkweiVL00;~=JfiSM2cE4W^|FPH0`?_T7VOC z^J6#Q7TqN*7qy#uyHhy{BqYRy3T!-5vFJUf7lqIkRe$S6N0>A#KU-=cP&!dBF<2T;4O z`z9gn2t1-c-u^4G+tO2rYlp24QDWQ1MuWAmuo7BdQ;E}MAj5@tv69k>FqI)=nA;Bq zkcbwE<>sw*8xzS~fwU%oGg{0^y)ILmr7}?_+)Jot*Nn-5tV);DvG=tVq0_OSzv!(m z>tRzI8*#-DJflb1ORS zCjhbMWKume;AHXqKR7LrJ(h4YwfPccuso3CMGpa7Roy6_e}y~vr0FkH@KbN!HL3!h$uUJD6(7zEPb8H0Tu~MKf^5#)e}Y(sg-4)*t5Ad&k6M z0z|zdn7Tfd?>4lS);!pC1n-C79&Ya9^r(G*dm-iM%0w#g!h0pmB>QTg511qZw$H5U zxg76bOD?{-ob{|eF(il6bH{^;6kctVMx?!YCXbYEoMZPd&KV|gN#Ld!x_uRCWe?Z5 zerkNL?*3@>k?WF%^a-T&(k+`)IgDKt#@d#sQls;LaK6bkLxxPA|WiWWXpAz?UQcS?U681R+ zeC}WF)!iRg=4iZdn4txZ#iMHiXLz*;?i>=bf~UnN=WXv+2k$K%1z8NS&AQh)`2(#O z3*nayTY?8@h_chv&Gxl1JSVShNKl7SFKGH>R&L-RA?){o9ap>=0I;;rT_zs0Bv*o2 zfJW67>Ci#mpoBBL-K#?SKBl;H+(?V`CYxyS)S&CpGI_F;65603ZM{*cxh|_iQ}ova z*rEJPhk>LcO?}+Lxo1T>i^L=k%RF0S>|;&0lz;mP%8`MK04^c) zFh?-fWr!k?!vZGdkgW^kC(c|Gj^pzN!|;#``10|a+>2=4AW z2^!qp-Q696y9bBh7Tn$4-QC^Y?&O^F-M#zmKKtw){-Ecrp6cpquliNLMOpV>)Txf= z>2kSqZ5|##!`4SENy;&&Ich!FN&0xA{8Uz@kJqzq-lt!%d2VBr#eJM85UJF7bCNFc zS%PMMjQ?Dp-(fdDW}|jFqa#U?m4bnF@;v$(%X%uLY`Do;2jjD`hWaU`4g^OT$8f^Z zx6EypVT5!iecoS%r3xII&x$^`@T`5lTMD>|fr%N5nV~l}{m?^uIbGYJ`5icDZ&P4@ z$8KMM&{=TU%R!%`Hjy2Tdb?cLTZ?pmPM~12tXj3)wTPFPPiXE*S4+{W0h3tTYUxbD z6+ZtBS-mN*L>{c2^fz(+BT1>6oen7E$^+4XA;luod zvMF2$x~W{kF?VA|s?3Xu#r+}gx+lWks^affR9HIQuXJy3twf6_j-o^HZZ!fyc;kb& z&2hn59ObuP$!LIcL3icQ7cIDYmz}!qjExi87)3L&i2DnaskSm$XjI^2BZ_ZdU|~iz zDKSrPhgsX}$%?;(MGpPzojkKKTHn3+x@v8LR`EH%HyPRlSNtyQ#(pFZ{mz$jhuv%--R+Gj-n+ORk~M=~k0HE+HT4<{kSNql2mqH2W(ZHt7~d z$qxiDPn3yAtRar@#k-#`H9KX74al5yKi;*C-3Q7Fwd|*lq3jw-x%!m*s9Mrs)MyafvoLlJkymUME6thpsTxN6Z5C>YGC5DqE01R6`}t8H zyb7l+yiCq7-P7ARMknS|-TFpGMX!s`GCJ*Yv#$sI=dUifUgBOt+8VvvavQs;Hqu{; z{IFNXhZ{IzJf1^$T~36|siU$NSe__midHH!lh2Jde--bd8D<}*M6@2!GJ|HGTcNUM zD2$tLCDeS9$j+Y%+6QM$<}3>hC9?~9nP~}L4#R~Sv!Fnp2RuBOd$Tk->X=B0aF?4W{J0?oe0bX; z`K;~*r4pIT^?e+rLiroh!JUhK;E3B%w&+t23xRcGCENotUl2@*&F80h(bFU}Fjr8~ z$6I+?AQs;_J}m-k;Yp7njKXik;nyA$uYvm(OARZx03N-T;)p5~kvn%yV7-+RXV}Q# zRSGGMPTuvJQElC^X;bbH;EMNII%{%BI=n))t2BJ%dx;m$P#PwAdrzodvT2~4rZ*}a z>c^8Fs|}97T?FNrdkmF_v4&Esf3n+Ney{g~Nv5hj9c<80F)3*$tX+VU9GwACz~NCG zVbxP?@Zj4P37XM?sG7(mqKEKbf8n~||8VK{FaN?)wmZd!-s-N2Ek>7B zd;qt1K487$Gp{ogO-~>a1bRQINZy1%Gqr>~)cj40KA!4_imPO-AF z@l~F#6JU)Hn9sGQ^VBO}w7#9w{-ys=GEfVbkGH1(TfCIXXaE!o1h&~vN+m`O{6ldV z(Vu~GCuH(l0vzyoV9S@cQyyzE%EbaCy?Sk(&I`=#E5xNaqxclLT`jAWs^&A5GKzBNGvZU6!BnlyjM;LO1GUu!kli zxIt%1pfl#8P^99#=B2NrI6`Shgf48+BE{#6Y;13=7H;ZLVeP0rz>GzXB+J|GsOdQ^ zXt~zb+i(ic5-+aC1$}a==)PI*(b0N5im9X0TMpe>dR*$y)33P=CI%ox3Ose(G#<9o zD%VlXw&L#cJQ!6InQcjPx?Qg$0o*l668qh6;fb92G`_yE1lD?D<#|^{3r!2L;Roo@ z+?PwE+xuag%>#jr9lPo<557hm>Dl?bf7d+I#UO{miQ>=QASZ)1f3eqCmFj zo9V!RS(bEcLodsf4_6MWe|ApK_FnvrCY83am*JFHy8@aJmDat>5E*-H8>c=3yzGZG zMzNn1r@I^(&XFHxPMT+;dcOeFR1I#U{Ie7Q)nm`$bWvSq1n`lhbw+-OuDI%eAdy*2 z2Sy86P4>*3Z~lr;-T6xD1Ak5q!k<(Smz4DH_5Z z4#aj5qiH`9wIK_{*D%N=c3sDZE0&$S-=9+WA!E9~AnNGNudAuui0sUth&h>Hw&qV- zV<$Y*Rif!*!7(uN!02GLAG2M~;s=MsU2i zAx?o8T4!0SfqGAbN(IX{mQONMZ8X0*O};J?h1pde@w!=g+=jnY@`g;Fo!@*Rg>Uke z_SP+Y8;#Als=h3PYo|NmeP(3bkjIOsWMk3Dh_vBmznZjA%ZG$T5We-c*IB&dZi5yp zE%1l%cJIN{S(c8;OMqK~<3XNS6v*zLRql48%T)$T)Q{Lo?>@*|J`X%+GRc$aLem?W zo|TNcBYdiYfK%Rk8%&Z38AdC(SNGz0hY5+8vLZ`Yn)vIl3EQmZk1J=+#EA%&u44Ik zLi|-bc&l?GXalB&9j(e^U)=zxhNYiU{8 z`mpF{71DN*DI#!$9V<6hPF_Vsqw1XW&ohK+t??mncnh#~5t#+J{*UMJ-Av}dwUKU9 zO{uZt{MuQzUnel;A_&;R1IWj-i=R1sSd`k$7)<=OH|5sGu&iKRPR(d?m5Gv$+$@z{ zn74IHt8n3lDr;<;GC~UrY^h`$)_WkEyCgA%%rzA)AX3b%)sqrpSrvMJ(+0h;RXU

    oO+@+-Qv2hx8uRC=I{7yNW4lj9Sl5RHHUbrF2hfah zziZV=L9n#XbwfVv+rHapAbUySH0&~4gnpxEKThOS*+9zvm1|W^b`=#pbtyvRbdR-E zSc~jcgV@3^sn5bDj|_Hk>wfxY!Pe)%^kMTvGf#8dh2;~5sWS$YGum^Bmg!ZV(h@~k zYjGiPTrn~5z7iV&ov-Zaa_(^juY5i|9NRO4Tl5`jhUVq>wYwVx(kAwU#PKHOM z9LrNF5zv&q-8%)4uo7ti<5-W~vCvnKypMQzM&A)8eTS;cMKq4R$*_-~5 z-Q$UhX?u~8V`I#S<&ZM&oJVIpFCv|?p~>Rf2W0A3UmfomiRZFjrEg0OJHAs3pUNCX>n0^S6&*n&&=|tjVo;Q2lMbW zV#e$t`Au+d^5TGyRNv!}6>``Q<%f0esIf|o!r%W>fktHOsl;IhmmT_YO{PL z{BE}mfZtb_2M7v|nzN-O+jK{8VSnj?8PtAPa(vz=M~L=H*-W$RIrzXp{ zG~_(XN}sIJia0(;-oOdEeBnY|Fi&{8Eq=7b$9wNbRael=0!TBcJ z5avj->z|KIu&Kz+-}r*&0nz@767(|>$q~U%dXue N=ri#_p|4?j2k0O5*!UO@-QM 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�Vc00tY;;{4=>8;2BHUkpUF8@usZnIOwl{My< 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 DhBLik literal 0 HcmV?d00001 diff --git a/tests/tools/dhcp-ubench/performance-results.ods b/tests/tools/dhcp-ubench/performance-results.ods index 918b739cc20983dc7d59bdb80242fc5cf3fc1f15..b9c68bf93a37f79ce112a3f3cfe3597e6f00de96 100644 GIT binary patch literal 48268 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

    c7+5UOU1lbxOUCU{aeJ66ut zuxCn^4M7-k9I#cu&(UeZx4ve3`u@{MdGXw11KPlRBU>HmcN!xOmn7&W{&ZUn`5DMy zJx;s)HeeHTjQ#3{#Eq_iEE@(Hxl3rcOVT?1DhQ^b0}_f1pYQ^U;VK)JA;ZO6Ppu%h z-{i>v_CTumn|iS?Vt&y{?YOeA{6~yE0@uj8NH!y(0pO;fGJ$Xw*uj;6fUXf$yMHe{IWau*Y%-Ay)2!%ttI zwkKJmXUj6Hx5`)#9l~Z%o7nq=IE5FX6OATFN-Jz^8PQ+xp45^7KY`XVbb)S%Aj~= z=-bzvZp_YFAEjd%E`@zu;Bpbl(yYV&6{Y@FSc%I}e?X5RK~4Hob|llzPbYuqaOlxl z8uZA{FY^7q+3@39eugyJ3LD=N)FOlPwX3jY3;{F8OwvWTOUw+`)L!oJtgu`V>2K#E zsEUVev3fp~PMLryhXTCNT3u4&*}8l-BOZ^YljIpg26D#$#2=aL<|$=O9<3bd`%!M8 z#G&hKC8=`!b8%2!b>qQKO0g6l#2yyx?esYlObN~zyul)cN!Pbz!#h8^r|~T9hgmn? zPy?fw3AnQ_Ak+~AOsgExEVSO*HR zXK=%YB#zw@kxRlECQUn>qHM^voXXl%5|oLE(v6N^){2ncyyCp`CQ~uhr$Xl5k`tkg zLPyU8$xkAGI>}FZXrP(hGNX`@Ww{V zg!tyYG8*;U%8Wi}OO{ezYCi2rAFw8BDm5w1H)+d1sWo(ZMbs&vDqZus3Ao}*wG8By zT8KAO{`OHp-nJ1oJS_W)W;H><4|lrcT9P?HQX0elr&mDUsAA_??2%+XVS1%d6SYLs1R(1B=HpN60Elj3NTkE7 z*Oc$2u`^~S_x_X;5C676`*0==MzMyk-av{#p>sDlM;n`w;Af-xn|C-VFT0ak!eoV6 zRG~A(u?a31Q5x8BlyE6+cDyg};qmGuts;y^o!&(_bt=O%Z5oX3I0mnEt;>#H#jUdGq6#6C)2*zUVNf9BmNYJz~XHb2hDV7ra9xR=JC1Wx3pBK3(vIQBhq(H{(|4yaxlUR$%yCJ$W-=4nOHk{Tx{@|m%%ES zRw)2uZ0yq)HUq$fEs4Tp1j!Erx1=yrq4;zEazAPPlUDE(E5`709y>V_YYQJCan26*4&Lkq!=D(Z-i!zsx~9<0DS-u8QL$FgkPT3r7P!Uu>4Wr03-flB1s#$8|?V$26CK%OaHy59k zzJUDQaW(|$;;`-qjb4Db;~W!jfUAdzK;4}3IOL%ttQY4x?^!)0?}vn?kB9v|5;oe4 z>(}rn4Yw}(mo9*;Sgr(SaqofY$Y^s$nU$3A*ELJXN`55)Ogm>2T5bIhYcrC5s*kT6 z-q*K(6k1Z-9`{#YU|F1lsaKXT0P#duSem51@<3Xs=#Prn@ll&?6FF%9-xEXw_?|-D`4>2$e zWPc0MH{e0^vBroukp8RC|M(pQ1H<``B4A+g>@kB1cqso{``7N40Z^tU!-h`sZ z(3K$muO+OS@gNS~#8Lf~{%4oOJtnY(;Qy3S$vvj6gn;(%MgJXQ`%laMcvJk7sQ<41 zS%$jDT$Ox?d2B|2`=i7^PiYKt3)ZJCcQ7zpJ7+U}TSg~yvwv&h-|~L{M-RdLFL~&G VF`6yJNPoJFAT$`*sQ;g{{|{-hy}ked From 8d2f900a8a8db49df9d7ad6fb26c02c3235b22b0 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Wed, 29 Aug 2012 12:20:44 -0700 Subject: [PATCH 062/148] [2098] [master] add cppcheck suppression rule for an intentional self-equivalence test okayed on jabber. --- src/lib/dns/tests/labelsequence_unittest.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc index 5eb49416d0..28f624aabd 100644 --- a/src/lib/dns/tests/labelsequence_unittest.cc +++ b/src/lib/dns/tests/labelsequence_unittest.cc @@ -180,6 +180,7 @@ TEST_F(LabelSequenceTest, equals_insensitive) { // operator==(). This is mostly trivial wrapper, so it should suffice to // check some basic cases. TEST_F(LabelSequenceTest, operatorEqual) { + // cppcheck-suppress duplicateExpression EXPECT_TRUE(ls1 == ls1); // self equivalence EXPECT_TRUE(ls1 == LabelSequence(n1)); // equivalent two different objects EXPECT_FALSE(ls1 == ls2); // non equivalent objects From b166b6061c760ccef7fd83ec354f6338d88162ee Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Thu, 30 Aug 2012 16:43:57 -0700 Subject: [PATCH 063/148] [2098] silence cppcheck warnings they are basically false positives, but addressing them is not difficult so I modified the code rather than suppressing them. --- src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc | 1 + src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc b/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc index c5cdef6675..bc418e85c9 100644 --- a/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc +++ b/src/lib/datasrc/memory/benchmarks/rrset_render_bench.cc @@ -151,6 +151,7 @@ buildZone(isc::util::MemorySegmentLocal& mem_sgmt, if ((it + 1) != rrsets.end() && (*(it + 1))->getType() == RRType::RRSIG()) { sig_rrset = *(++it); + assert(it != rrsets.end()); // to be safe, and silence cppcheck } RdataSet* rdataset = RdataSet::create(mem_sgmt, encoder, rrset, sig_rrset); diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc index cf486bf9da..33df2ebe36 100644 --- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc +++ b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc @@ -70,7 +70,10 @@ protected: "match.example.com. 3600 IN RRSIG " "A 5 2 3600 20120814220826 20120715220826 " "1234 example.com. FAKE")), - zone_data_(NULL) + zone_data_(NULL), origin_node_(NULL), www_node_(NULL), + wildcard_node_(NULL), ns_rdataset_(NULL), dname_rdataset_(NULL), + a_rdataset_(NULL), aaaa_rdataset_(NULL), rrsig_only_rdataset_(NULL), + wildcard_rdataset_(NULL) {} void SetUp() { // We create some common test data here in SetUp() so it will be From e8ec4c911eb69b969df42a60fb28d5f727b8a937 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Thu, 30 Aug 2012 16:58:34 -0700 Subject: [PATCH 064/148] [2098] make sure unexpected method call doesn't happen by exception/assert --- src/lib/datasrc/memory/rdata_serialization.cc | 1 + src/lib/dns/benchmarks/message_renderer_bench.cc | 6 +++++- src/lib/dns/benchmarks/oldmessagerenderer.cc | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib/datasrc/memory/rdata_serialization.cc b/src/lib/datasrc/memory/rdata_serialization.cc index 6c3e06c35b..6ac18d0e6a 100644 --- a/src/lib/datasrc/memory/rdata_serialization.cc +++ b/src/lib/datasrc/memory/rdata_serialization.cc @@ -250,6 +250,7 @@ public: virtual void setCompressMode(CompressMode) {} virtual void writeName(const LabelSequence&, bool) { // We don't need this version of writeName + isc_throw(Unexpected, "unexpected version of writeName is called"); } // Called for each domain name in the RDATA, from the RDATA's toWire() diff --git a/src/lib/dns/benchmarks/message_renderer_bench.cc b/src/lib/dns/benchmarks/message_renderer_bench.cc index 752b1f664c..6376498087 100644 --- a/src/lib/dns/benchmarks/message_renderer_bench.cc +++ b/src/lib/dns/benchmarks/message_renderer_bench.cc @@ -116,7 +116,11 @@ public: virtual void writeName(const Name& name, const bool = false) { name.toWire(getBuffer()); } - virtual void writeName(const LabelSequence&, const bool) {} // unused + virtual void writeName(const LabelSequence&, const bool) { + // We shouldn't use this version of writeName (and we internally + // control it, so we simply assert it here) + assert(false); + } }; void diff --git a/src/lib/dns/benchmarks/oldmessagerenderer.cc b/src/lib/dns/benchmarks/oldmessagerenderer.cc index a6c7990115..ed575a083f 100644 --- a/src/lib/dns/benchmarks/oldmessagerenderer.cc +++ b/src/lib/dns/benchmarks/oldmessagerenderer.cc @@ -277,7 +277,9 @@ OldMessageRenderer::writeName(const Name& name, const bool compress) { void OldMessageRenderer::writeName(const LabelSequence&, const bool) { - // we don't use this mode for the benchmark + // We shouldn't use this version of writeName (and we internally + // control it, so we simply assert it here) + assert(false); } } From 04c06cecc291057718100127c381c8385aaa9e92 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Thu, 30 Aug 2012 17:01:08 -0700 Subject: [PATCH 065/148] [2098] editorial cleanup: removed unnecessary postfix in variable names --- .../memory/tests/treenode_rrset_unittest.cc | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc index 33df2ebe36..e2531d640f 100644 --- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc +++ b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc @@ -221,30 +221,30 @@ TEST_F(TreeNodeRRsetTest, toWire) { { SCOPED_TRACE("with RRSIG, DNSSEC OK"); - const TreeNodeRRset rrset1(rrclass_, www_node_, a_rdataset_, true); - checkToWireResult(expected_renderer, actual_renderer, rrset1, + const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true); + checkToWireResult(expected_renderer, actual_renderer, rrset, www_name_, a_rrset_, a_rrsig_rrset_, true); } { SCOPED_TRACE("with RRSIG, DNSSEC not OK"); - const TreeNodeRRset rrset2(rrclass_, www_node_, a_rdataset_, false); - checkToWireResult(expected_renderer, actual_renderer, rrset2, + const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, false); + checkToWireResult(expected_renderer, actual_renderer, rrset, www_name_, a_rrset_, a_rrsig_rrset_, false); } { SCOPED_TRACE("without RRSIG, DNSSEC OK"); - const TreeNodeRRset rrset3(rrclass_, origin_node_, ns_rdataset_, true); - checkToWireResult(expected_renderer, actual_renderer, rrset3, + const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_, true); + checkToWireResult(expected_renderer, actual_renderer, rrset, origin_name_, ns_rrset_, ConstRRsetPtr(), true); } { SCOPED_TRACE("without RRSIG, DNSSEC not OK"); - const TreeNodeRRset rrset4(rrclass_, origin_node_, ns_rdataset_, - false); - checkToWireResult(expected_renderer, actual_renderer, rrset4, + const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_, + false); + checkToWireResult(expected_renderer, actual_renderer, rrset, origin_name_, ns_rrset_, ConstRRsetPtr(), false); } @@ -252,9 +252,9 @@ TEST_F(TreeNodeRRsetTest, toWire) { // RDATA of DNAME DR shouldn't be compressed. Prepending "example.org" // will check that. SCOPED_TRACE("uncompressed RDATA"); - const TreeNodeRRset rrset5(rrclass_, origin_node_, dname_rdataset_, - false); - checkToWireResult(expected_renderer, actual_renderer, rrset5, + const TreeNodeRRset rrset(rrclass_, origin_node_, dname_rdataset_, + false); + checkToWireResult(expected_renderer, actual_renderer, rrset, Name("example.org"), dname_rrset_, ConstRRsetPtr(), false); } @@ -283,9 +283,9 @@ TEST_F(TreeNodeRRsetTest, toWire) { // ANY or type-RRSIG queries, which are rare also). But can still // happen. SCOPED_TRACE("RRSIG only, DNSSEC OK"); - const TreeNodeRRset rrset6(rrclass_, www_node_, rrsig_only_rdataset_, - true); - checkToWireResult(expected_renderer, actual_renderer, rrset6, + const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_, + true); + checkToWireResult(expected_renderer, actual_renderer, rrset, www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,true); } @@ -294,9 +294,9 @@ TEST_F(TreeNodeRRsetTest, toWire) { // In practice this case wouldn't happen, but API-wise possible, so // we test it explicitly. SCOPED_TRACE("RRSIG only, DNSSEC not OK"); - const TreeNodeRRset rrset7(rrclass_, www_node_, rrsig_only_rdataset_, - false); - checkToWireResult(expected_renderer, actual_renderer, rrset7, + const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_, + false); + checkToWireResult(expected_renderer, actual_renderer, rrset, www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,false); } } From 8440ca544d013e4081c4e0762cdb88c9888c0af5 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 09:43:15 +0900 Subject: [PATCH 066/148] [2098] unified the normal and truncation toWire test cases. --- .../memory/tests/treenode_rrset_unittest.cc | 140 ++++++++++-------- 1 file changed, 79 insertions(+), 61 deletions(-) diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc index e2531d640f..13f36d271e 100644 --- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc +++ b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc @@ -180,34 +180,73 @@ TEST_F(TreeNodeRRsetTest, create) { match_name_, rrclass_, RRType::A(), 2, 1); } -// Templated if and when we support OutputBuffer version of toWire(). -// Right now, we take a minimalist approach, only implementing testing the -// renderer version. +// The following two templated functions are helper to encapsulate the +// concept truncation and handle MessageRenderer and OutputBuffer transparently +// in templated test cases. +template +void +setOutputLengthLimit(OutputType& output, size_t len_limit) { + output.setLengthLimit(len_limit); +} +template <> +void +setOutputLengthLimit(OutputBuffer&, size_t) { +} + +template +bool +isOutputTruncated(OutputType& output) { + return (output.isTruncated()); +} +template <> +bool +isOutputTruncated(OutputBuffer&) { + return (false); +} + +// Templated so we so can support OutputBuffer version of toWire(). +// We use the above helper templated functions for some renderer only methods. +// We test two sets of cases: normal rendering case and case when truncation +// is expected. The latter is effectively for MessageRenderer only. +// If len_limit == 0, we consider it the normal case; otherwise it's for +// truncation. prepended_name isn't used for the truncation case. template void checkToWireResult(OutputType& expected_output, OutputType& actual_output, const AbstractRRset& actual_rrset, const Name& prepended_name, ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset, - bool dnssec_ok) + bool dnssec_ok, + size_t len_limit = 0, + size_t expected_result = 0) { expected_output.clear(); actual_output.clear(); - // Prepare "actual" rendered data. We prepend a name to confirm the - // owner name should be compressed in both cases. - prepended_name.toWire(actual_output); - const size_t rdata_count = rrset ? rrset->getRdataCount() : 0; - const int expected_ret = (dnssec_ok && rrsig_rrset) ? - rdata_count + rrsig_rrset->getRdataCount() : rdata_count; - EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output)); + if (len_limit == 0) { // normal rendering + // Prepare "actual" rendered data. We prepend a name to confirm the + // owner name should be compressed in both cases. + prepended_name.toWire(actual_output); + const size_t rdata_count = rrset ? rrset->getRdataCount() : 0; + const int expected_ret = (dnssec_ok && rrsig_rrset) ? + rdata_count + rrsig_rrset->getRdataCount() : rdata_count; + EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output)); + } else { // truncation + setOutputLengthLimit(actual_output, len_limit); + EXPECT_EQ(expected_result, actual_rrset.toWire(actual_output)); + EXPECT_TRUE(isOutputTruncated(actual_output)); // always true here + } // Prepare "expected" data. - prepended_name.toWire(expected_output); + if (len_limit == 0) { // normal rendering + prepended_name.toWire(expected_output); + } else { // truncation + setOutputLengthLimit(expected_output, len_limit); + } if (rrset) { rrset->toWire(expected_output); } - if (dnssec_ok && rrsig_rrset) { + if (!isOutputTruncated(expected_output) && dnssec_ok && rrsig_rrset) { rrsig_rrset->toWire(expected_output); } @@ -218,12 +257,18 @@ checkToWireResult(OutputType& expected_output, OutputType& actual_output, TEST_F(TreeNodeRRsetTest, toWire) { MessageRenderer expected_renderer, actual_renderer; + OutputBuffer expected_buffer(0), actual_buffer(0); { SCOPED_TRACE("with RRSIG, DNSSEC OK"); const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true); checkToWireResult(expected_renderer, actual_renderer, rrset, www_name_, a_rrset_, a_rrsig_rrset_, true); + // Currently the buffer version throws + EXPECT_THROW( + checkToWireResult(expected_buffer, actual_buffer, rrset, + www_name_, a_rrset_, a_rrsig_rrset_, true), + isc::Unexpected); } { @@ -301,53 +346,27 @@ TEST_F(TreeNodeRRsetTest, toWire) { } } -void -checkTruncationResult(MessageRenderer& expected_renderer, - MessageRenderer& actual_renderer, - const AbstractRRset& actual_rrset, - ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset, - bool dnssec_ok, size_t len_limit, size_t expected_result) -{ - expected_renderer.clear(); - actual_renderer.clear(); - - actual_renderer.setLengthLimit(len_limit); - EXPECT_EQ(expected_result, actual_rrset.toWire(actual_renderer)); - EXPECT_TRUE(actual_renderer.isTruncated()); // always true in this test - - expected_renderer.setLengthLimit(len_limit); - if (rrset) { - rrset->toWire(expected_renderer); - } - if (!expected_renderer.isTruncated() && dnssec_ok && rrsig_rrset) { - rrsig_rrset->toWire(expected_renderer); - } - - matchWireData(expected_renderer.getData(), expected_renderer.getLength(), - actual_renderer.getData(), actual_renderer.getLength()); -} - TEST_F(TreeNodeRRsetTest, toWireTruncated) { MessageRenderer expected_renderer, actual_renderer; + // dummy parameter to checkToWireResult (unused for the this test case) + const Name& name = Name::ROOT_NAME(); // Set the truncation limit to name len + 14 bytes of fixed data for A RR // (type, class, TTL, rdlen, and 4-byte IPv4 address). Then we can only // render just one RR, without any garbage trailing data. - checkTruncationResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, a_rdataset_, - true), - a_rrset_, a_rrsig_rrset_, true, - www_name_.getLength() + 14, - 1); // 1 main RR, no RRSIG + checkToWireResult(expected_renderer, actual_renderer, + TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true), + name, a_rrset_, a_rrsig_rrset_, true, + www_name_.getLength() + 14, + 1); // 1 main RR, no RRSIG // The first main RRs should fit in the renderer (the name will be // fully compressed, so its size is 2 bytes), but the RRSIG doesn't. - checkTruncationResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, a_rdataset_, - true), - a_rrset_, a_rrsig_rrset_, true, - www_name_.getLength() + 14 + 2 + 14, - 2); // 2 main RR, no RRSIG + checkToWireResult(expected_renderer, actual_renderer, + TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true), + name, a_rrset_, a_rrsig_rrset_, true, + www_name_.getLength() + 14 + 2 + 14, + 2); // 2 main RR, no RRSIG // This RRset has one main RR and two RRSIGs. Rendering the second RRSIG // causes truncation. @@ -359,19 +378,18 @@ TEST_F(TreeNodeRRsetTest, toWireTruncated) { a_rrsig_rrset_->toWire(expected_renderer); const size_t limit_len = expected_renderer.getLength(); // Then perform the test - checkTruncationResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, aaaa_rdataset_, - true), - aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len, - 2); // 1 main RR, 1 RRSIG + checkToWireResult(expected_renderer, actual_renderer, + TreeNodeRRset(rrclass_, www_node_, aaaa_rdataset_, true), + name, aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len, + 2); // 1 main RR, 1 RRSIG // RRSIG only case. Render length limit being 1, so it won't fit, // and will cause truncation. - checkTruncationResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, - rrsig_only_rdataset_, true), - ConstRRsetPtr(), txt_rrsig_rrset_, true, 1, - 0); // no RR + checkToWireResult(expected_renderer, actual_renderer, + TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_, + true), + name, ConstRRsetPtr(), txt_rrsig_rrset_, true, 1, + 0); // no RR } void From cb4c5b31b47ea1062cb74077ff5788f192d60eac Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 09:57:53 +0900 Subject: [PATCH 067/148] [2098] try to improve in-method comments for isSameKind() --- src/lib/datasrc/memory/treenode_rrset.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc index 6fc6b66682..11898a3f26 100644 --- a/src/lib/datasrc/memory/treenode_rrset.cc +++ b/src/lib/datasrc/memory/treenode_rrset.cc @@ -339,11 +339,12 @@ TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const { if (rdataset_ != other->rdataset_) { return (false); } - // Same for the owner name (note: in practice this method would be - // called for rrsets at different nodes, so we check that condition - // first). Note also that based on the basic assumption of the - // ZoneTree, if the nodes are different their RR classes must be - // different. + // Same for the owner name. Comparing the nodes also detect + // the case where RR classes are different (see the method description + // of the header for details). + // hasSameRealName() is a bit more complicated and we expect the + // two nodes are often different here in practice, so we check that + // condition first. if (node_ != other->node_ || !hasSameRealName(*other)) { return (false); } From a92987802f0f8106a6c1e2fbf41adb53d8ba67fa Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 10:16:15 +0900 Subject: [PATCH 068/148] [2098] use a real name object for real name instead of serialized labelseqs It will simplify various parts of the code. Name object is expensive, but either way it involves memory allocation anyway, so performance impact wouldn't be much different. --- src/lib/datasrc/memory/treenode_rrset.cc | 57 +++++++----------------- src/lib/datasrc/memory/treenode_rrset.h | 21 +++++---- 2 files changed, 26 insertions(+), 52 deletions(-) diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc index 11898a3f26..c6219781a5 100644 --- a/src/lib/datasrc/memory/treenode_rrset.cc +++ b/src/lib/datasrc/memory/treenode_rrset.cc @@ -40,22 +40,11 @@ namespace isc { namespace datasrc { namespace memory { -TreeNodeRRset::TreeNodeRRset(const dns::Name& realname, - const dns::RRClass& rrclass, - const ZoneNode* node, const RdataSet* rdataset, - bool dnssec_ok) : - node_(node), rdataset_(rdataset), - rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass), - dnssec_ok_(dnssec_ok), name_(NULL) -{ - const LabelSequence labels(realname); - const size_t labels_storangelen = labels.getSerializedLength(); - realname_buf_ = new uint8_t[labels_storangelen]; - labels.serialize(realname_buf_, labels_storangelen); -} - const Name& TreeNodeRRset::getName() const { + if (realname_ != NULL) { + return (*realname_); + } if (name_ == NULL) { uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH]; const LabelSequence name_labels = getOwnerLabels(labels_buf); @@ -342,10 +331,19 @@ TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const { // Same for the owner name. Comparing the nodes also detect // the case where RR classes are different (see the method description // of the header for details). - // hasSameRealName() is a bit more complicated and we expect the - // two nodes are often different here in practice, so we check that - // condition first. - if (node_ != other->node_ || !hasSameRealName(*other)) { + if (node_ != other->node_ ) { + return (false); + } + // If one is constructed with a "real name" and the other isn't + // *we consider* them different. + if ((realname_ == NULL && other->realname_ != NULL) || + (realname_ != NULL && other->realname_ == NULL)) { + return (false); + } + // If both are constructed with a "real name", we compare their names + // (as label sequences) explicitly. + if (realname_ != NULL && other->realname_ != NULL && + realname_->nequals(*other->realname_)) { return (false); } return (true); @@ -353,29 +351,6 @@ TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const { return (AbstractRRset::isSameKind(abs_other)); } -bool -TreeNodeRRset::hasSameRealName(const TreeNodeRRset& other) const { - // If one is constructed with a "real name" and the other isn't - // *we consider* them different. - if ((realname_buf_ == NULL && other.realname_buf_ != NULL) || - (realname_buf_ != NULL && other.realname_buf_ == NULL)) { - return (false); - } - - // If both are constructed with a "real name", we compare their names - // (as label sequences) explicitly. - if (realname_buf_ != NULL && other.realname_buf_ != NULL) { - uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH]; - uint8_t other_labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH]; - if (!getOwnerLabels(labels_buf).equals( - other.getOwnerLabels(other_labels_buf))) { - return (false); - } - } - - return (true); -} - } // namespace memory } // namespace datasrc } // datasrc isc diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h index 1f52124386..7567ae16a5 100644 --- a/src/lib/datasrc/memory/treenode_rrset.h +++ b/src/lib/datasrc/memory/treenode_rrset.h @@ -105,7 +105,7 @@ public: const RdataSet* rdataset, bool dnssec_ok) : node_(node), rdataset_(rdataset), rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass), - dnssec_ok_(dnssec_ok), name_(NULL), realname_buf_(NULL) + dnssec_ok_(dnssec_ok), name_(NULL), realname_(NULL) {} /// \brief Constructor for wildcard-expanded owner name. @@ -122,10 +122,14 @@ public: /// \throw std::bad_alloc Memory allocation fails TreeNodeRRset(const dns::Name& realname, const dns::RRClass& rrclass, const ZoneNode* node, const RdataSet* rdataset, - bool dnssec_ok); + bool dnssec_ok) : + node_(node), rdataset_(rdataset), + rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass), + dnssec_ok_(dnssec_ok), name_(NULL), realname_(new dns::Name(realname)) + {} virtual ~TreeNodeRRset() { - delete[] realname_buf_; + delete realname_; delete name_; } @@ -233,24 +237,19 @@ private: dns::LabelSequence getOwnerLabels( uint8_t labels_buf[dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const { - if (realname_buf_ != NULL) { - return (dns::LabelSequence(realname_buf_)); + if (realname_ != NULL) { + return (dns::LabelSequence(*realname_)); } return (node_->getAbsoluteLabels(labels_buf)); } - // A helper for isSameKind() to check if 'this' and 'other' has - // the same "real" name in case at least either is constructed with - // a real name. - bool hasSameRealName(const TreeNodeRRset& other) const; - const ZoneNode* node_; const RdataSet* rdataset_; const size_t rrsig_count_; const dns::RRClass rrclass_; const bool dnssec_ok_; mutable dns::Name* name_; - uint8_t* realname_buf_; + const dns::Name* const realname_; }; } // namespace memory From 19e4b209bd92898239781336796e9dd339dde415 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 10:18:23 +0900 Subject: [PATCH 069/148] [2098] cleanup: removed commented-out unused method parameter. --- src/lib/datasrc/memory/treenode_rrset.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc index c6219781a5..840d202063 100644 --- a/src/lib/datasrc/memory/treenode_rrset.cc +++ b/src/lib/datasrc/memory/treenode_rrset.cc @@ -195,7 +195,7 @@ TreeNodeRRset::toWire(AbstractMessageRenderer& renderer) const { } unsigned int -TreeNodeRRset::toWire(isc::util::OutputBuffer& /*buffer*/) const { +TreeNodeRRset::toWire(isc::util::OutputBuffer&) const { isc_throw(Unexpected, "unexpected method called on TreeNodeRRset"); } From e0bdb21d3bc3e0c4c23df61fe204bb6e35fa4057 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 10:28:40 +0900 Subject: [PATCH 070/148] [2098] explicitly confirm unexpected method calls result in exception. --- .../memory/tests/treenode_rrset_unittest.cc | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc index 13f36d271e..b95e706b42 100644 --- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc +++ b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc @@ -544,4 +544,25 @@ TEST_F(TreeNodeRRsetTest, isSameKind) { // Different kind of different RRset class EXPECT_FALSE(rrset.isSameKind(*aaaa_rrset_)); } + +TEST_F(TreeNodeRRsetTest, unexpectedMethods) { + // Note: buffer version of toWire() is checked in the toWire test. + + TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true); + + EXPECT_THROW(rrset.getTTL(), isc::Unexpected); + EXPECT_THROW(rrset.setTTL(RRTTL(0)), isc::Unexpected); + EXPECT_THROW(rrset.setName(Name("example")), isc::Unexpected); + EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")), + isc::Unexpected); + EXPECT_THROW(rrset.getRRsig(), isc::Unexpected); + RdataPtr sig_rdata = createRdata( + RRType::RRSIG(), rrclass_, + "A 5 2 3600 20120814220826 20120715220826 5300 example.com. FAKE"); + EXPECT_THROW(rrset.addRRsig(sig_rdata), isc::Unexpected); + EXPECT_THROW(rrset.addRRsig(*a_rrsig_rrset_), isc::Unexpected); + EXPECT_THROW(rrset.addRRsig(a_rrsig_rrset_), isc::Unexpected); + EXPECT_THROW(rrset.addRRsig(RRsetPtr()), isc::Unexpected); + EXPECT_THROW(rrset.removeRRsig(), isc::Unexpected); +} } From 740e0113d51fe26a7683477e7e0e19d1390119eb Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 10:32:13 +0900 Subject: [PATCH 071/148] [2098] a minor grammar fix in document --- src/lib/datasrc/memory/treenode_rrset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h index 7567ae16a5..2ad3a3c289 100644 --- a/src/lib/datasrc/memory/treenode_rrset.h +++ b/src/lib/datasrc/memory/treenode_rrset.h @@ -75,7 +75,7 @@ public: /// \brief Normal case constructor. /// /// This class object is basically defined with a \c ZoneNode and - /// \c RdataSet. The former determine the owner name of the RRset, + /// \c RdataSet. The former determines the owner name of the RRset, /// and the latter provides the rest of the RRset parameters. /// Since the RR class is maintained outside of the \c ZoneData, /// it must be explicitly given as a constructor parameter. From 49aabed090bd58b4aa295af86f106adbe2d5492b Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Fri, 31 Aug 2012 10:58:29 +0900 Subject: [PATCH 072/148] [2098] one minor comment update reflecting recent code changes --- src/lib/datasrc/memory/treenode_rrset.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc index 840d202063..5c333ff009 100644 --- a/src/lib/datasrc/memory/treenode_rrset.cc +++ b/src/lib/datasrc/memory/treenode_rrset.cc @@ -341,7 +341,7 @@ TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const { return (false); } // If both are constructed with a "real name", we compare their names - // (as label sequences) explicitly. + // explicitly. if (realname_ != NULL && other->realname_ != NULL && realname_->nequals(*other->realname_)) { return (false); From f2408e01aa158c250e4b1638bd77c45448957436 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Fri, 31 Aug 2012 10:33:51 +0200 Subject: [PATCH 073/148] Changelog for #2188 --- ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8036119b55..933cab255d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +471. [bug] vorner + Fixed a problem when b10-loadzone tried to tread semicolon in string data + as start of comment, which caused invalid data being loaded. + (Trac #2188, git 12efec3477feb62d7cbe36bdcfbfc7aa28a36f57) + 470. [func] naokikambe The stats module now supports partial statistics updates. Each module can return only statistics data which have been updated since From 6c9732dc5b937177c1989fffe12970d5f08fb8f0 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Fri, 31 Aug 2012 13:58:02 +0200 Subject: [PATCH 074/148] [357] address review comments - explain 0 value for tcp_recv_timeout - initialize value in config parser (to 0, it will be set by build() anyway) --- doc/guide/bind10-guide.xml | 1 + src/bin/auth/auth_config.cc | 8 ++++++-- src/bin/auth/b10-auth.xml | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index 61cddd6ff4..cbdad93489 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -1640,6 +1640,7 @@ can use various data source backends. tcp_recv_timeout is the timeout used on incoming TCP connections, in milliseconds. If the query is not sent within this time, the connection is closed. + Setting this to 0 will disable TCP timeouts completely. diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc index 6cc356e792..e8592ac553 100644 --- a/src/bin/auth/auth_config.cc +++ b/src/bin/auth/auth_config.cc @@ -120,11 +120,15 @@ private: /// \brief Configuration for TCP receive timeouts class TCPRecvTimeoutConfig : public AuthConfigParser { public: - TCPRecvTimeoutConfig(AuthSrv& server) : server_(server) + TCPRecvTimeoutConfig(AuthSrv& server) : server_(server), timeout_(0) {} virtual void build(ConstElementPtr config) { - timeout_ = config->intValue(); + if (config->intValue() >= 0) { + timeout_ = config->intValue(); + } else { + isc_throw(AuthConfigError, "tcp_recv_timeout must be 0 or higher"); + } } virtual void commit() { diff --git a/src/bin/auth/b10-auth.xml b/src/bin/auth/b10-auth.xml index 556873c86b..b34009d039 100644 --- a/src/bin/auth/b10-auth.xml +++ b/src/bin/auth/b10-auth.xml @@ -156,6 +156,7 @@ tcp_recv_timeout is the timeout used on incoming TCP connections, in milliseconds. If the query is not sent within this time, the connection is closed. + Setting this to 0 will disable TCP timeouts completely. From c1f4e353392c6dfaa23370010972ce97354e12c3 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Fri, 31 Aug 2012 14:26:56 +0200 Subject: [PATCH 075/148] [357] test for negative timeout config --- src/bin/auth/tests/config_unittest.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc index 84f86b4fc2..830de0d92d 100644 --- a/src/bin/auth/tests/config_unittest.cc +++ b/src/bin/auth/tests/config_unittest.cc @@ -151,6 +151,9 @@ TEST_F(AuthConfigTest, tcpRecvTimeoutConfig) { configureAuthServer(server, Element::fromJSON( "{ \"tcp_recv_timeout\": 2000 }")); EXPECT_EQ(2000, dnss_.getTCPRecvTimeout()); + EXPECT_THROW(configureAuthServer(server, Element::fromJSON( + "{ \"tcp_recv_timeout\": -123 }")), + AuthConfigError); } } From 5119bf75e932910f872098a65ec76063c142f5c2 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Fri, 31 Aug 2012 15:35:36 +0200 Subject: [PATCH 076/148] [357] set default tcp recv timeout to 5 seconds --- src/bin/auth/auth.spec.pre.in | 2 +- src/lib/asiodns/dns_service.cc | 2 +- src/lib/asiodns/tcp_server.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in index 3c31c2d86e..a471b7a87f 100644 --- a/src/bin/auth/auth.spec.pre.in +++ b/src/bin/auth/auth.spec.pre.in @@ -94,7 +94,7 @@ { "item_name": "tcp_recv_timeout", "item_type": "integer", "item_optional": false, - "item_default": 1000 + "item_default": 5000 } ], "commands": [ diff --git a/src/lib/asiodns/dns_service.cc b/src/lib/asiodns/dns_service.cc index 03ec09dba7..f72d24b493 100644 --- a/src/lib/asiodns/dns_service.cc +++ b/src/lib/asiodns/dns_service.cc @@ -40,7 +40,7 @@ public: DNSServiceImpl(IOService& io_service, SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) : io_service_(io_service), checkin_(checkin), lookup_(lookup), - answer_(answer), tcp_recv_timeout_(1000) + answer_(answer), tcp_recv_timeout_(5000) {} IOService& io_service_; diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc index c291b6ff93..ed3f28cecc 100644 --- a/src/lib/asiodns/tcp_server.cc +++ b/src/lib/asiodns/tcp_server.cc @@ -72,7 +72,7 @@ TCPServer::TCPServer(io_service& io_service, int fd, int af, } // Set it to some value. It should be set to the right one // immediately, but set it to something non-zero just in case. - tcp_recv_timeout_.reset(new size_t(1000)); + tcp_recv_timeout_.reset(new size_t(5000)); } namespace { From 156ac2bc58f707e87820c26d548603923e997efe Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 09:21:24 -0500 Subject: [PATCH 077/148] [master] add missing dist file detected by distcheck failure: http://git.bind10.isc.org/~tester/builder/BIND10-distcheck/20120831093000-FreeBSD8-i386/logs/distcheck.out discussed on jabber --- src/lib/datasrc/tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am index f3be2e1967..26e1ca4655 100644 --- a/src/lib/datasrc/tests/Makefile.am +++ b/src/lib/datasrc/tests/Makefile.am @@ -105,6 +105,7 @@ EXTRA_DIST += testdata/contexttest.zone EXTRA_DIST += testdata/diffs.sqlite3 EXTRA_DIST += testdata/example2.com EXTRA_DIST += testdata/example2.com.sqlite3 +EXTRA_DIST += testdata/example.com.flattened EXTRA_DIST += testdata/example.com.signed EXTRA_DIST += testdata/example.org EXTRA_DIST += testdata/example.org.nsec3-signed From 53c587e48d0ba91757f33be4b79868596cdf6aad Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 09:34:22 -0500 Subject: [PATCH 078/148] [master] add another missing dist file The tests didn't fail due to missing file. See memory_datasrc_unittest.cc: EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"), ... EXPECT_THROW(rootzone.load(TEST_DATA_DIR "/duplicate_rrset.zone"), I assume this is a false-negative because the test successds because loading still fails. Maybe that test or "load" should be extended for this, but for now I add the missing file to EXTRA_DIST. --- src/lib/datasrc/tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am index 26e1ca4655..b73a64a703 100644 --- a/src/lib/datasrc/tests/Makefile.am +++ b/src/lib/datasrc/tests/Makefile.am @@ -103,6 +103,7 @@ endif EXTRA_DIST = testdata/brokendb.sqlite3 EXTRA_DIST += testdata/contexttest.zone EXTRA_DIST += testdata/diffs.sqlite3 +EXTRA_DIST += testdata/duplicate_rrset.zone EXTRA_DIST += testdata/example2.com EXTRA_DIST += testdata/example2.com.sqlite3 EXTRA_DIST += testdata/example.com.flattened From f328475860c3e2d69ec002a58fdc49e95e54619d Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Fri, 31 Aug 2012 17:22:59 +0200 Subject: [PATCH 079/148] [2160] Automatically clean message after processMessage() --- src/bin/auth/auth_srv.cc | 17 +++++++++++++++++ src/bin/auth/tests/auth_srv_unittest.cc | 7 +++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc index 6e5666f43f..b2383ca599 100644 --- a/src/bin/auth/auth_srv.cc +++ b/src/bin/auth/auth_srv.cc @@ -114,6 +114,18 @@ private: MessageRenderer& renderer_; }; +// Similar to Renderer holder, this is a very basic RAII-style class +// that calls clear(Message::PARSE) on the given Message upon destruction +class MessageHolder { +public: + MessageHolder(Message& message) : message_(message) {} + ~MessageHolder() { + message_.clear(Message::PARSE); + } +private: + Message& message_; +}; + // A helper container of socket session forwarder. // // This class provides a simple wrapper interface to SocketSessionForwarder @@ -344,6 +356,11 @@ public: OutputBufferPtr buffer, DNSServer* server) const { + // Keep a holder on the message, so that it is automatically + // cleared if processMessage() is done + // This is not done in processMessage itself (which would be + // equivalent), to allow tests to inspect the message handling. + MessageHolder message_holder(*message); server_->processMessage(io_message, *message, *buffer, server); } private: diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc index ca4247372b..e86cca4cb9 100644 --- a/src/bin/auth/tests/auth_srv_unittest.cc +++ b/src/bin/auth/tests/auth_srv_unittest.cc @@ -104,10 +104,6 @@ protected: } ~AuthSrvTest() { - // Clear the message now; depending on the RTTI implementation, - // type information may be lost if the message is cleared - // automatically later, so as a precaution we do it now. - parse_message->clear(Message::PARSE); server.destroyDDNSForwarder(); } @@ -833,6 +829,9 @@ TEST_F(AuthSrvTest, builtInQueryViaDNSServer) { response_obuffer->getData(), response_obuffer->getLength(), &response_data[0], response_data.size()); + + // After it has been run, the message should be cleared + EXPECT_EQ(0, parse_message->getRRCount(Message::SECTION_QUESTION)); } // In the following tests we confirm the response data is rendered in From 852e369ac1e1c6d91dcfeadc13ffb69d99c90576 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 11:10:58 -0500 Subject: [PATCH 080/148] [master] regenerate log messages docs --- doc/guide/bind10-messages.html | 66 ++++++++------------ doc/guide/bind10-messages.xml | 107 ++++++++++++--------------------- 2 files changed, 61 insertions(+), 112 deletions(-) diff --git a/doc/guide/bind10-messages.html b/doc/guide/bind10-messages.html index cfa27a660c..7ae8622483 100644 --- a/doc/guide/bind10-messages.html +++ b/doc/guide/bind10-messages.html @@ -1,10 +1,10 @@ -BIND 10 Messages Manual

    BIND 10 Messages Manual

    This is the messages manual for BIND 10 version - 20120712.

    Abstract

    BIND 10 is a Domain Name System (DNS) suite managed by +BIND 10 Messages Manual

    BIND 10 Messages Manual

    This is the messages manual for BIND 10 version + 20120817.

    Abstract

    BIND 10 is a Domain Name System (DNS) suite managed by Internet Systems Consortium (ISC). It includes DNS libraries and modular components for controlling authoritative and recursive DNS servers.

    - This is the messages manual for BIND 10 version 20120712. + This is the messages manual for BIND 10 version 20120817. The most up-to-date version of this document, along with other documents for BIND 10, can be found at http://bind10.isc.org/docs. @@ -154,10 +154,6 @@ This debug message is logged by the authoritative server when it receives a NOTIFY packet that an RR type of something other than SOA in the question section. (The RR type received is included in the message.) The server will return a FORMERR error to the sender. -

    AUTH_NO_STATS_SESSION session interface for statistics is not available

    -The authoritative server had no session with the statistics module at the -time it attempted to send it data: the attempt has been abandoned. This -could be an error in configuration.

    AUTH_NO_XFRIN received NOTIFY but XFRIN session is not running

    This is a debug message produced by the authoritative server when it receives a NOTIFY packet but the XFRIN process is not running. The packet will be @@ -193,11 +189,6 @@ This is a debug message issued when the authoritative server has received a command on the command channel.

    AUTH_RECEIVED_NOTIFY received incoming NOTIFY for zone name %1, zone class %2

    This is a debug message reporting that an incoming NOTIFY was received. -

    AUTH_RECEIVED_SENDSTATS command 'sendstats' received

    -This is a debug message issued when the authoritative server has received -a command from the statistics module to send it data. The 'sendstats' -command is handled differently to other commands, which is why the debug -message associated with it has its own code.

    AUTH_RESPONSE_FAILURE exception while building response to query: %1

    This is a debug message, generated by the authoritative server when an attempt to create a response to a received DNS packet has failed. The @@ -222,7 +213,7 @@ Note: This message includes the packet sent, rendered in the form of multiple lines of text. For this reason, it is suggested that this log message not be routed to the syslog file, where the multiple lines could confuse programs that expect a format of one message per line. -

    AUTH_SEND_NORMAL_RESPONSE sending an error response (%1 bytes):\n%2

    +

    AUTH_SEND_NORMAL_RESPONSE sending a normal response (%1 bytes):\n%2

    This is a debug message recording that the authoritative server is sending a response to the originator of a query.

    @@ -254,31 +245,6 @@ that it should internally forward UPDATE message to b10-ddns. When b10-ddns is not running, b10-auth will respond to UPDATE requests with rcode NOTIMP. When b10-ddns is running, b10-ddns will handle and respond to the UPDATE message. -

    AUTH_STATS_CHANNEL_CREATED STATS session channel created

    -This is a debug message indicating that the authoritative server has -created a channel to the statistics process. It is issued during server -startup is an indication that the initialization is proceeding normally. -

    AUTH_STATS_CHANNEL_ESTABLISHED STATS session channel established

    -This is a debug message indicating that the authoritative server -has established communication over the previously created statistics -channel. It is issued during server startup is an indication that the -initialization is proceeding normally. -

    AUTH_STATS_COMMS communication error in sending statistics data: %1

    -An error was encountered when the authoritative server tried to send data -to the statistics daemon. The message includes additional information -describing the reason for the failure. -

    AUTH_STATS_TIMEOUT timeout while sending statistics data: %1

    -The authoritative server sent data to the statistics daemon but received -no acknowledgement within the specified time. The message includes -additional information describing the reason for the failure. -

    AUTH_STATS_TIMER_DISABLED statistics timer has been disabled

    -This is a debug message indicating that the statistics timer has been -disabled in the authoritative server and no statistics information is -being produced. -

    AUTH_STATS_TIMER_SET statistics timer set to %1 second(s)

    -This is a debug message indicating that the statistics timer has been -enabled and that the authoritative server will produce statistics data -at the specified interval.

    AUTH_STOP_DDNS_FORWARDER DDNS UPDATE handling stopped

    This is a debug message indicating that b10-auth has received a message that it should stop internally forwarding UPDATE message to b10-ddns. @@ -1111,6 +1077,10 @@ is provided as a master file and it can be served from memory cache only. Therefore, the zone will not be available for this process. If this is a problem, you should move the zone to some database backend (sqlite3, for example) and use it from there. +

    DATASRC_MASTERLOAD_ERROR %1

    +An error was found in the zone data for a MasterFiles zone. The zone +is not loaded. The specific error is shown in the message, and should +be addressed.

    DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'

    Debug information. An RRset is being added to the in-memory data source.

    DATASRC_MEM_ADD_WILDCARD adding wildcards for '%1'

    @@ -1479,10 +1449,19 @@ for and not found, the software searches for the "previous" name, example.com). However, this name is not contained in any zone in the data source. This is an error since it indicates a problem in the earlier processing of the query. -

    DATASRC_SQLITE_SETUP setting up SQLite database

    +

    DATASRC_SQLITE_SETUP setting up new SQLite3 database in '%1'

    The database for SQLite data source was found empty. It is assumed this is the first run and it is being initialized with current schema. It'll still contain -no data, but it will be ready for use. +no data, but it will be ready for use. If this is indeed the first run of +BIND 10, it is to be expected and completely harmless. If you just configured +a data source to point to an existing file and you see this, you may have +misspelled the file name. +

    DATASRC_SQLITE_SETUP_OLD_API setting up new SQLite database

    +The database for SQLite data source was found empty. It is assumed this is the +first run and it is being initialized with current schema. It'll still contain +no data, but it will be ready for use. This is similar to DATASRC_SQLITE_SETUP +message, but it is logged from the old API. You should never see it, since the +API is deprecated.

    DATASRC_STATIC_CLASS_NOT_CH static data source can handle CH class only

    An error message indicating that a query requesting a RR for a class other that CH was sent to the static data source (which only handles CH queries). @@ -2773,6 +2752,9 @@ not start. The stats module was unable to connect to the BIND 10 command and control bus. A likely problem is that the message bus daemon (b10-msgq) is not running. The stats module will now shut down. +

    STATS_RECEIVED_INVALID_STATISTICS_DATA received invalid statistics data from %1

    +Invalid statistics data has been received from the module while +polling and it has been discarded.

    STATS_RECEIVED_NEW_CONFIG received new configuration: %1

    This debug message is printed when the stats module has received a configuration update from the configuration manager. @@ -2794,8 +2776,8 @@ response indicating that it is running normally.

    STATS_RECEIVED_UNKNOWN_COMMAND received unknown command: %1

    An unknown command has been sent to the stats module. The stats module will respond with an error and the command will be ignored. -

    STATS_SEND_REQUEST_BOSS requesting boss to send statistics

    -This debug message is printed when a request is sent to the boss module +

    STATS_SEND_STATISTICS_REQUEST requesting %1 to send statistics

    +This debug message is printed when a request is sent to the module to send its data to the stats module.

    STATS_STARTING starting

    The stats module will be now starting. diff --git a/doc/guide/bind10-messages.xml b/doc/guide/bind10-messages.xml index 79dfe655ad..bdbc8c6d31 100644 --- a/doc/guide/bind10-messages.xml +++ b/doc/guide/bind10-messages.xml @@ -341,15 +341,6 @@ server will return a FORMERR error to the sender. - -AUTH_NO_STATS_SESSION session interface for statistics is not available - -The authoritative server had no session with the statistics module at the -time it attempted to send it data: the attempt has been abandoned. This -could be an error in configuration. - - - AUTH_NO_XFRIN received NOTIFY but XFRIN session is not running @@ -465,7 +456,7 @@ programs that expect a format of one message per line. -AUTH_SEND_NORMAL_RESPONSE sending an error response (%1 bytes):\n%2 +AUTH_SEND_NORMAL_RESPONSE sending a normal response (%1 bytes):\n%2 This is a debug message recording that the authoritative server is sending a response to the originator of a query. @@ -531,61 +522,6 @@ message. - -AUTH_STATS_CHANNEL_CREATED STATS session channel created - -This is a debug message indicating that the authoritative server has -created a channel to the statistics process. It is issued during server -startup is an indication that the initialization is proceeding normally. - - - - -AUTH_STATS_CHANNEL_ESTABLISHED STATS session channel established - -This is a debug message indicating that the authoritative server -has established communication over the previously created statistics -channel. It is issued during server startup is an indication that the -initialization is proceeding normally. - - - - -AUTH_STATS_COMMS communication error in sending statistics data: %1 - -An error was encountered when the authoritative server tried to send data -to the statistics daemon. The message includes additional information -describing the reason for the failure. - - - - -AUTH_STATS_TIMEOUT timeout while sending statistics data: %1 - -The authoritative server sent data to the statistics daemon but received -no acknowledgement within the specified time. The message includes -additional information describing the reason for the failure. - - - - -AUTH_STATS_TIMER_DISABLED statistics timer has been disabled - -This is a debug message indicating that the statistics timer has been -disabled in the authoritative server and no statistics information is -being produced. - - - - -AUTH_STATS_TIMER_SET statistics timer set to %1 second(s) - -This is a debug message indicating that the statistics timer has been -enabled and that the authoritative server will produce statistics data -at the specified interval. - - - AUTH_STOP_DDNS_FORWARDER DDNS UPDATE handling stopped @@ -2508,6 +2444,15 @@ example) and use it from there. + +DATASRC_MASTERLOAD_ERROR %1 + +An error was found in the zone data for a MasterFiles zone. The zone +is not loaded. The specific error is shown in the message, and should +be addressed. + + + DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3' @@ -3422,11 +3367,25 @@ processing of the query. -DATASRC_SQLITE_SETUP setting up SQLite database +DATASRC_SQLITE_SETUP setting up new SQLite3 database in '%1' The database for SQLite data source was found empty. It is assumed this is the first run and it is being initialized with current schema. It'll still contain -no data, but it will be ready for use. +no data, but it will be ready for use. If this is indeed the first run of +BIND 10, it is to be expected and completely harmless. If you just configured +a data source to point to an existing file and you see this, you may have +misspelled the file name. + + + + +DATASRC_SQLITE_SETUP_OLD_API setting up new SQLite database + +The database for SQLite data source was found empty. It is assumed this is the +first run and it is being initialized with current schema. It'll still contain +no data, but it will be ready for use. This is similar to DATASRC_SQLITE_SETUP +message, but it is logged from the old API. You should never see it, since the +API is deprecated. @@ -6045,6 +6004,14 @@ control bus. A likely problem is that the message bus daemon + +STATS_RECEIVED_INVALID_STATISTICS_DATA received invalid statistics data from %1 + +Invalid statistics data has been received from the module while +polling and it has been discarded. + + + STATS_RECEIVED_NEW_CONFIG received new configuration: %1 @@ -6106,10 +6073,10 @@ will respond with an error and the command will be ignored. - -STATS_SEND_REQUEST_BOSS requesting boss to send statistics + +STATS_SEND_STATISTICS_REQUEST requesting %1 to send statistics -This debug message is printed when a request is sent to the boss module +This debug message is printed when a request is sent to the module to send its data to the stats module. From 8ca0f76d6b42aeb5b76f5390b64be89719f03cb2 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 11:18:01 -0500 Subject: [PATCH 081/148] [1687] add missing man page This has not been reviewed. Let's consider it a stub for now. --- src/bin/sockcreator/b10-sockcreator.xml | 96 +++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/bin/sockcreator/b10-sockcreator.xml diff --git a/src/bin/sockcreator/b10-sockcreator.xml b/src/bin/sockcreator/b10-sockcreator.xml new file mode 100644 index 0000000000..6c51debd2b --- /dev/null +++ b/src/bin/sockcreator/b10-sockcreator.xml @@ -0,0 +1,96 @@ +]> + + + + + + February 28, 2012 + + + + b10-sockcreator + 8 + BIND10 + + + + b10-sockcreator + socket creation daemon + + + + + 2012 + Internet Systems Consortium, Inc. ("ISC") + + + + + + b10-sockcreator + + + + + DESCRIPTION + + The b10-sockcreator daemon's entire job + is to create sockets and assign names to them. + It is started by + bind108 + and communicates with it. + The new socket is sent over a file descriptor. + + + + + + The b10-sockcreator daemon will exit + if there is an unrecoverable error or unknown command. + + + + + + SEE ALSO + + + bind108 + , + BIND 10 Guide. + + + + + + AUTHORS + + The b10-sockcreator daemon + was initially designed by Michal Vaner of CZNIC. + + + + + + + From c0c5ff359f557d5a11533fb605e7cb613a1cea78 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 13:48:14 -0500 Subject: [PATCH 082/148] [master] fix spelling Fix a misspelling in a log output. Also fix same misspelling in some comments and unittest output. --- src/bin/auth/command.cc | 2 +- src/lib/datasrc/tests/database_unittest.cc | 4 ++-- src/lib/datasrc/tests/memory_datasrc_unittest.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin/auth/command.cc b/src/bin/auth/command.cc index 0658c17b0e..43b242269e 100644 --- a/src/bin/auth/command.cc +++ b/src/bin/auth/command.cc @@ -210,7 +210,7 @@ public: case ConfigurableClientList::ZONE_NOT_CACHED: isc_throw(AuthCommandError, "Zone " << origin << "/" << zone_class << " is not served from memory, but " - "direcly from the data source. It is not possible " + "directly from the data source. It is not possible " "to reload it into memory. Configure it to be cached " "first."); case ConfigurableClientList::CACHE_DISABLED: diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc index 56ee5dd171..dda4de2b29 100644 --- a/src/lib/datasrc/tests/database_unittest.cc +++ b/src/lib/datasrc/tests/database_unittest.cc @@ -2153,7 +2153,7 @@ TYPED_TEST(DatabaseClientTest, findDelegation) { this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_, this->expected_sig_rdatas_); - // And when we ask direcly for the NS, we should still get delegation + // And when we ask directly for the NS, we should still get delegation doFindTest(*finder, isc::dns::Name("delegation.example.org."), isc::dns::RRType::NS(), isc::dns::RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION, this->expected_rdatas_, @@ -2184,7 +2184,7 @@ TYPED_TEST(DatabaseClientTest, findDelegation) { this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT, isc::dns::Name("dname.example.org.")); - // Asking direcly for DNAME should give SUCCESS + // Asking directly for DNAME should give SUCCESS doFindTest(*finder, isc::dns::Name("dname.example.org."), isc::dns::RRType::DNAME(), isc::dns::RRType::DNAME(), this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_, diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc index 5abe2702a2..fcdca16a86 100644 --- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc +++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc @@ -1511,7 +1511,7 @@ InMemoryZoneFinderTest::anyWildcardCheck( // First try directly the name (normal match) { - SCOPED_TRACE("Asking direcly for *"); + SCOPED_TRACE("Asking directly for *"); expected_sets.push_back(rr_wild_); findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS, expected_sets); From 525ad8cdd617d4bc98a303371b87b3e009a1c268 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 14:02:30 -0500 Subject: [PATCH 083/148] [master] add entry for 1687 --- ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 933cab255d..3b0f58b6b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +472. [build] jreed + All generated documentation is removed from the git repository. + The ./configure --enable-man option is removed. A new option + -enable-generate-docs is added; it checks for required + documentation building dependencies. Dummy documentation is + built and installed if not used. Distributed tarballs will + contain the generated documentation. + (Trac #1687, git 2d4063b1a354f5048ca9dfb195e8e169650f43d0) + 471. [bug] vorner Fixed a problem when b10-loadzone tried to tread semicolon in string data as start of comment, which caused invalid data being loaded. From a7ec11d025a5d25452868862458a5a39da97b77f Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 14:03:10 -0500 Subject: [PATCH 084/148] [master] fix some changelog formatting for previous entry --- ChangeLog | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b0f58b6b3..af508216f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,9 +7,10 @@ contain the generated documentation. (Trac #1687, git 2d4063b1a354f5048ca9dfb195e8e169650f43d0) -471. [bug] vorner - Fixed a problem when b10-loadzone tried to tread semicolon in string data - as start of comment, which caused invalid data being loaded. +471. [bug] vorner + Fixed a problem when b10-loadzone tried to tread semicolon + in string data as start of comment, which caused invalid + data being loaded. (Trac #2188, git 12efec3477feb62d7cbe36bdcfbfc7aa28a36f57) 470. [func] naokikambe From 70b15138139170a7d94323ad80628ed1865e5176 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 14:50:09 -0500 Subject: [PATCH 085/148] [master] use MAINTAINERCLEANFILES for man pages Use "make maintainer-clean" instead of "make distclean" to remove the manpages. This fixes problem where enduser using tarball does a "make clean" and loses the maintainer-tarball-provided manpages. --- doc/guide/Makefile.am | 2 +- src/bin/auth/Makefile.am | 2 +- src/bin/bind10/Makefile.am | 2 +- src/bin/bindctl/Makefile.am | 2 +- src/bin/cfgmgr/Makefile.am | 2 +- src/bin/cmdctl/Makefile.am | 2 +- src/bin/dbutil/Makefile.am | 2 +- src/bin/ddns/Makefile.am | 2 +- src/bin/dhcp4/Makefile.am | 2 +- src/bin/dhcp6/Makefile.am | 2 +- src/bin/host/Makefile.am | 2 +- src/bin/loadzone/Makefile.am | 2 +- src/bin/msgq/Makefile.am | 2 +- src/bin/resolver/Makefile.am | 2 +- src/bin/sockcreator/Makefile.am | 2 +- src/bin/stats/Makefile.am | 2 +- src/bin/sysinfo/Makefile.am | 2 +- src/bin/usermgr/Makefile.am | 2 +- src/bin/xfrin/Makefile.am | 2 +- src/bin/xfrout/Makefile.am | 2 +- src/bin/zonemgr/Makefile.am | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index 36b12bc107..e234b8351a 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -6,7 +6,7 @@ dist_doc_DATA = $(DOCS) dist_html_DATA = $(HTMLDOCS) bind10-guide.css EXTRA_DIST = bind10-guide.xml -CLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml +MAINTAINERCLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml # This is not a "man" manual, but reuse this for now for docbook. if GENERATE_DOCS diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index 34b3661d38..f95fb0834d 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -20,7 +20,7 @@ CLEANFILES = *.gcno *.gcda auth.spec spec_config.h CLEANFILES += auth_messages.h auth_messages.cc man_MANS = b10-auth.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-auth.xml if GENERATE_DOCS diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am index 10f9918016..5b3828ebee 100644 --- a/src/bin/bind10/Makefile.am +++ b/src/bin/bind10/Makefile.am @@ -17,7 +17,7 @@ bind10_DATA = bob.spec EXTRA_DIST = bob.spec man_MANS = bind10.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) bind10.xml bind10_messages.mes if GENERATE_DOCS diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am index a4c6dddadd..d4c1e9678c 100644 --- a/src/bin/bindctl/Makefile.am +++ b/src/bin/bindctl/Makefile.am @@ -14,7 +14,7 @@ pythondir = $(pyexecdir)/bindctl bindctldir = $(pkgdatadir) CLEANFILES = bindctl bindctl_main.pyc -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am index dae688bf99..89706a111a 100644 --- a/src/bin/cfgmgr/Makefile.am +++ b/src/bin/cfgmgr/Makefile.am @@ -10,7 +10,7 @@ b10_cfgmgrdir = @localstatedir@/@PACKAGE@ #B10_cfgmgr_DATA = man_MANS = b10-cfgmgr.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cfgmgr.xml if GENERATE_DOCS diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am index 7b2c21e70b..048e09ebda 100644 --- a/src/bin/cmdctl/Makefile.am +++ b/src/bin/cmdctl/Makefile.am @@ -26,7 +26,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.pyc man_MANS = b10-cmdctl.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes if GENERATE_DOCS diff --git a/src/bin/dbutil/Makefile.am b/src/bin/dbutil/Makefile.am index 701ee799f3..62628e2e06 100644 --- a/src/bin/dbutil/Makefile.am +++ b/src/bin/dbutil/Makefile.am @@ -14,7 +14,7 @@ CLEANFILES = b10-dbutil b10-dbutil.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyo -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/ddns/Makefile.am b/src/bin/ddns/Makefile.am index c9570bd7cf..05ebe92048 100644 --- a/src/bin/ddns/Makefile.am +++ b/src/bin/ddns/Makefile.am @@ -17,7 +17,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/ddns_messages.pyc EXTRA_DIST = ddns_messages.mes ddns.spec man_MANS = b10-ddns.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST += $(man_MANS) b10-ddns.xml if GENERATE_DOCS diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index 769a50ed58..5fc9913ea5 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -15,7 +15,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp4.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec if GENERATE_DOCS diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 94ec90652e..23373cc75d 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -16,7 +16,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp6.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec if GENERATE_DOCS diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am index c5e6959b11..28d42f41fe 100644 --- a/src/bin/host/Makefile.am +++ b/src/bin/host/Makefile.am @@ -17,7 +17,7 @@ b10_host_LDADD += $(top_builddir)/src/lib/util/libb10-util.la b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la man_MANS = b10-host.1 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-host.xml .PHONY: man diff --git a/src/bin/loadzone/Makefile.am b/src/bin/loadzone/Makefile.am index fc1f8a806b..6288770378 100644 --- a/src/bin/loadzone/Makefile.am +++ b/src/bin/loadzone/Makefile.am @@ -5,7 +5,7 @@ noinst_SCRIPTS = run_loadzone.sh CLEANFILES = b10-loadzone man_MANS = b10-loadzone.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-loadzone.xml if GENERATE_DOCS diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am index ef297e18c6..68e22970e1 100644 --- a/src/bin/msgq/Makefile.am +++ b/src/bin/msgq/Makefile.am @@ -7,7 +7,7 @@ pkglibexec_SCRIPTS = b10-msgq CLEANFILES = b10-msgq msgq.pyc man_MANS = b10-msgq.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) msgq.xml if GENERATE_DOCS diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index 3893335037..ed1e7458b0 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -23,7 +23,7 @@ CLEANFILES += resolver.spec spec_config.h CLEANFILES += resolver_messages.cc resolver_messages.h man_MANS = b10-resolver.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-resolver.xml resolver_messages.mes if GENERATE_DOCS diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index 9347d452ec..99ca3f4ab4 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -13,7 +13,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = *.gcno *.gcda man_MANS = b10-sockcreator.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-sockcreator.xml if GENERATE_DOCS diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am index c4acfc8762..bc91a31b3b 100644 --- a/src/bin/stats/Makefile.am +++ b/src/bin/stats/Makefile.am @@ -20,7 +20,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.pyc man_MANS = b10-stats.8 b10-stats-httpd.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-stats.xml b10-stats-httpd.xml EXTRA_DIST += stats.spec stats-httpd.spec EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl diff --git a/src/bin/sysinfo/Makefile.am b/src/bin/sysinfo/Makefile.am index c9b5d8edd1..c828637c5d 100644 --- a/src/bin/sysinfo/Makefile.am +++ b/src/bin/sysinfo/Makefile.am @@ -12,7 +12,7 @@ MAN1_FILES = \ man_MANS = \ $(MAN1_FILES:.xml=.1) -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am index 9d7a7c527c..f34fade7c3 100644 --- a/src/bin/usermgr/Makefile.am +++ b/src/bin/usermgr/Makefile.am @@ -5,7 +5,7 @@ b10_cmdctl_usermgrdir = $(pkgdatadir) CLEANFILES= b10-cmdctl-usermgr man_MANS = b10-cmdctl-usermgr.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cmdctl-usermgr.xml if GENERATE_DOCS diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am index eb2d0b9c1d..97adac7170 100644 --- a/src/bin/xfrin/Makefile.am +++ b/src/bin/xfrin/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.pyc man_MANS = b10-xfrin.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrin.xml EXTRA_DIST += xfrin.spec xfrin_messages.mes diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am index 9f8009e29c..85d43f46d0 100644 --- a/src/bin/xfrout/Makefile.am +++ b/src/bin/xfrout/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.pyc man_MANS = b10-xfrout.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrout.xml xfrout_messages.mes if GENERATE_DOCS diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am index 9fbdaeb8f2..ef03095b0c 100644 --- a/src/bin/zonemgr/Makefile.am +++ b/src/bin/zonemgr/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.pyc man_MANS = b10-zonemgr.8 -CLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES += $(man_MANS) EXTRA_DIST = $(man_MANS) b10-zonemgr.xml zonemgr_messages.mes if GENERATE_DOCS From 7d468f9c00be62cdab915edfca4d28e602a742a8 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 14:57:09 -0500 Subject: [PATCH 086/148] [master] fix MAINTAINERCLEANFILES fix my previous commit; sorry I tested wrong. This changes += to just = for first use of MAINTAINERCLEANFILES. --- src/bin/auth/Makefile.am | 2 +- src/bin/bind10/Makefile.am | 2 +- src/bin/bindctl/Makefile.am | 2 +- src/bin/cfgmgr/Makefile.am | 2 +- src/bin/cmdctl/Makefile.am | 2 +- src/bin/dbutil/Makefile.am | 2 +- src/bin/ddns/Makefile.am | 2 +- src/bin/dhcp4/Makefile.am | 2 +- src/bin/dhcp6/Makefile.am | 2 +- src/bin/host/Makefile.am | 2 +- src/bin/loadzone/Makefile.am | 2 +- src/bin/msgq/Makefile.am | 2 +- src/bin/resolver/Makefile.am | 2 +- src/bin/sockcreator/Makefile.am | 2 +- src/bin/stats/Makefile.am | 2 +- src/bin/sysinfo/Makefile.am | 2 +- src/bin/usermgr/Makefile.am | 2 +- src/bin/xfrin/Makefile.am | 2 +- src/bin/xfrout/Makefile.am | 2 +- src/bin/zonemgr/Makefile.am | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index f95fb0834d..83caf910ca 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -20,7 +20,7 @@ CLEANFILES = *.gcno *.gcda auth.spec spec_config.h CLEANFILES += auth_messages.h auth_messages.cc man_MANS = b10-auth.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-auth.xml if GENERATE_DOCS diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am index 5b3828ebee..21598f604e 100644 --- a/src/bin/bind10/Makefile.am +++ b/src/bin/bind10/Makefile.am @@ -17,7 +17,7 @@ bind10_DATA = bob.spec EXTRA_DIST = bob.spec man_MANS = bind10.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST += $(man_MANS) bind10.xml bind10_messages.mes if GENERATE_DOCS diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am index d4c1e9678c..b30dbc2145 100644 --- a/src/bin/bindctl/Makefile.am +++ b/src/bin/bindctl/Makefile.am @@ -14,7 +14,7 @@ pythondir = $(pyexecdir)/bindctl bindctldir = $(pkgdatadir) CLEANFILES = bindctl bindctl_main.pyc -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am index 89706a111a..d4617adbc3 100644 --- a/src/bin/cfgmgr/Makefile.am +++ b/src/bin/cfgmgr/Makefile.am @@ -10,7 +10,7 @@ b10_cfgmgrdir = @localstatedir@/@PACKAGE@ #B10_cfgmgr_DATA = man_MANS = b10-cfgmgr.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cfgmgr.xml if GENERATE_DOCS diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am index 048e09ebda..22e9951399 100644 --- a/src/bin/cmdctl/Makefile.am +++ b/src/bin/cmdctl/Makefile.am @@ -26,7 +26,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.pyc man_MANS = b10-cmdctl.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes if GENERATE_DOCS diff --git a/src/bin/dbutil/Makefile.am b/src/bin/dbutil/Makefile.am index 62628e2e06..5ace9d41fa 100644 --- a/src/bin/dbutil/Makefile.am +++ b/src/bin/dbutil/Makefile.am @@ -14,7 +14,7 @@ CLEANFILES = b10-dbutil b10-dbutil.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyo -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/ddns/Makefile.am b/src/bin/ddns/Makefile.am index 05ebe92048..f0ebf361c8 100644 --- a/src/bin/ddns/Makefile.am +++ b/src/bin/ddns/Makefile.am @@ -17,7 +17,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/ddns_messages.pyc EXTRA_DIST = ddns_messages.mes ddns.spec man_MANS = b10-ddns.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST += $(man_MANS) b10-ddns.xml if GENERATE_DOCS diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index 5fc9913ea5..3050c1c780 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -15,7 +15,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp4.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec if GENERATE_DOCS diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 23373cc75d..539ac23ed3 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -16,7 +16,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp6.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec if GENERATE_DOCS diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am index 28d42f41fe..d1f01f4e5c 100644 --- a/src/bin/host/Makefile.am +++ b/src/bin/host/Makefile.am @@ -17,7 +17,7 @@ b10_host_LDADD += $(top_builddir)/src/lib/util/libb10-util.la b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la man_MANS = b10-host.1 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-host.xml .PHONY: man diff --git a/src/bin/loadzone/Makefile.am b/src/bin/loadzone/Makefile.am index 6288770378..a37aeb15bd 100644 --- a/src/bin/loadzone/Makefile.am +++ b/src/bin/loadzone/Makefile.am @@ -5,7 +5,7 @@ noinst_SCRIPTS = run_loadzone.sh CLEANFILES = b10-loadzone man_MANS = b10-loadzone.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-loadzone.xml if GENERATE_DOCS diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am index 68e22970e1..5b981c4f61 100644 --- a/src/bin/msgq/Makefile.am +++ b/src/bin/msgq/Makefile.am @@ -7,7 +7,7 @@ pkglibexec_SCRIPTS = b10-msgq CLEANFILES = b10-msgq msgq.pyc man_MANS = b10-msgq.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) msgq.xml if GENERATE_DOCS diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index ed1e7458b0..7c1c849879 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -23,7 +23,7 @@ CLEANFILES += resolver.spec spec_config.h CLEANFILES += resolver_messages.cc resolver_messages.h man_MANS = b10-resolver.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-resolver.xml resolver_messages.mes if GENERATE_DOCS diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index 99ca3f4ab4..966d449965 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -13,7 +13,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = *.gcno *.gcda man_MANS = b10-sockcreator.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-sockcreator.xml if GENERATE_DOCS diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am index bc91a31b3b..0e2c3f6080 100644 --- a/src/bin/stats/Makefile.am +++ b/src/bin/stats/Makefile.am @@ -20,7 +20,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.pyc man_MANS = b10-stats.8 b10-stats-httpd.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-stats.xml b10-stats-httpd.xml EXTRA_DIST += stats.spec stats-httpd.spec EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl diff --git a/src/bin/sysinfo/Makefile.am b/src/bin/sysinfo/Makefile.am index c828637c5d..2329b0c9b4 100644 --- a/src/bin/sysinfo/Makefile.am +++ b/src/bin/sysinfo/Makefile.am @@ -12,7 +12,7 @@ MAN1_FILES = \ man_MANS = \ $(MAN1_FILES:.xml=.1) -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am index f34fade7c3..0dde3c0bfa 100644 --- a/src/bin/usermgr/Makefile.am +++ b/src/bin/usermgr/Makefile.am @@ -5,7 +5,7 @@ b10_cmdctl_usermgrdir = $(pkgdatadir) CLEANFILES= b10-cmdctl-usermgr man_MANS = b10-cmdctl-usermgr.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cmdctl-usermgr.xml if GENERATE_DOCS diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am index 97adac7170..cbe3bddb5c 100644 --- a/src/bin/xfrin/Makefile.am +++ b/src/bin/xfrin/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.pyc man_MANS = b10-xfrin.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrin.xml EXTRA_DIST += xfrin.spec xfrin_messages.mes diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am index 85d43f46d0..87d926ce28 100644 --- a/src/bin/xfrout/Makefile.am +++ b/src/bin/xfrout/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.pyc man_MANS = b10-xfrout.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrout.xml xfrout_messages.mes if GENERATE_DOCS diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am index ef03095b0c..58a0fff90c 100644 --- a/src/bin/zonemgr/Makefile.am +++ b/src/bin/zonemgr/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.pyc man_MANS = b10-zonemgr.8 -MAINTAINERCLEANFILES += $(man_MANS) +MAINTAINERCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-zonemgr.xml zonemgr_messages.mes if GENERATE_DOCS From b31ee71173d901621f6200e3e57179e9e6e13d5e Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 31 Aug 2012 18:43:41 -0500 Subject: [PATCH 087/148] [master] use DISTCLEANFILES instead of MAINTAINERCLEANFILES for docs --- doc/guide/Makefile.am | 2 +- src/bin/auth/Makefile.am | 2 +- src/bin/bind10/Makefile.am | 2 +- src/bin/bindctl/Makefile.am | 2 +- src/bin/cfgmgr/Makefile.am | 2 +- src/bin/cmdctl/Makefile.am | 2 +- src/bin/dbutil/Makefile.am | 2 +- src/bin/ddns/Makefile.am | 2 +- src/bin/dhcp4/Makefile.am | 2 +- src/bin/dhcp6/Makefile.am | 2 +- src/bin/host/Makefile.am | 2 +- src/bin/loadzone/Makefile.am | 2 +- src/bin/msgq/Makefile.am | 2 +- src/bin/resolver/Makefile.am | 2 +- src/bin/sockcreator/Makefile.am | 2 +- src/bin/stats/Makefile.am | 2 +- src/bin/sysinfo/Makefile.am | 2 +- src/bin/usermgr/Makefile.am | 2 +- src/bin/xfrin/Makefile.am | 2 +- src/bin/xfrout/Makefile.am | 2 +- src/bin/zonemgr/Makefile.am | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/guide/Makefile.am b/doc/guide/Makefile.am index e234b8351a..1d63c04b31 100644 --- a/doc/guide/Makefile.am +++ b/doc/guide/Makefile.am @@ -6,7 +6,7 @@ dist_doc_DATA = $(DOCS) dist_html_DATA = $(HTMLDOCS) bind10-guide.css EXTRA_DIST = bind10-guide.xml -MAINTAINERCLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml +DISTCLEANFILES = $(HTMLDOCS) $(DOCS) bind10-messages.xml # This is not a "man" manual, but reuse this for now for docbook. if GENERATE_DOCS diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am index 83caf910ca..9e24433d29 100644 --- a/src/bin/auth/Makefile.am +++ b/src/bin/auth/Makefile.am @@ -20,7 +20,7 @@ CLEANFILES = *.gcno *.gcda auth.spec spec_config.h CLEANFILES += auth_messages.h auth_messages.cc man_MANS = b10-auth.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-auth.xml if GENERATE_DOCS diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am index 21598f604e..86c6595424 100644 --- a/src/bin/bind10/Makefile.am +++ b/src/bin/bind10/Makefile.am @@ -17,7 +17,7 @@ bind10_DATA = bob.spec EXTRA_DIST = bob.spec man_MANS = bind10.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST += $(man_MANS) bind10.xml bind10_messages.mes if GENERATE_DOCS diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am index b30dbc2145..1134240bf4 100644 --- a/src/bin/bindctl/Makefile.am +++ b/src/bin/bindctl/Makefile.am @@ -14,7 +14,7 @@ pythondir = $(pyexecdir)/bindctl bindctldir = $(pkgdatadir) CLEANFILES = bindctl bindctl_main.pyc -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am index d4617adbc3..e9e0ccaf85 100644 --- a/src/bin/cfgmgr/Makefile.am +++ b/src/bin/cfgmgr/Makefile.am @@ -10,7 +10,7 @@ b10_cfgmgrdir = @localstatedir@/@PACKAGE@ #B10_cfgmgr_DATA = man_MANS = b10-cfgmgr.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cfgmgr.xml if GENERATE_DOCS diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am index 22e9951399..3b88f4b6c3 100644 --- a/src/bin/cmdctl/Makefile.am +++ b/src/bin/cmdctl/Makefile.am @@ -26,7 +26,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.pyc man_MANS = b10-cmdctl.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes if GENERATE_DOCS diff --git a/src/bin/dbutil/Makefile.am b/src/bin/dbutil/Makefile.am index 5ace9d41fa..4f6f1fa2d3 100644 --- a/src/bin/dbutil/Makefile.am +++ b/src/bin/dbutil/Makefile.am @@ -14,7 +14,7 @@ CLEANFILES = b10-dbutil b10-dbutil.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyc CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/dbutil_messages.pyo -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/ddns/Makefile.am b/src/bin/ddns/Makefile.am index f0ebf361c8..be2da552b7 100644 --- a/src/bin/ddns/Makefile.am +++ b/src/bin/ddns/Makefile.am @@ -17,7 +17,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/ddns_messages.pyc EXTRA_DIST = ddns_messages.mes ddns.spec man_MANS = b10-ddns.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST += $(man_MANS) b10-ddns.xml if GENERATE_DOCS diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index 3050c1c780..295ab41de7 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -15,7 +15,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp4.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec if GENERATE_DOCS diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index 539ac23ed3..f711c973cf 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -16,7 +16,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = spec_config.h man_MANS = b10-dhcp6.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec if GENERATE_DOCS diff --git a/src/bin/host/Makefile.am b/src/bin/host/Makefile.am index d1f01f4e5c..42ef954ce1 100644 --- a/src/bin/host/Makefile.am +++ b/src/bin/host/Makefile.am @@ -17,7 +17,7 @@ b10_host_LDADD += $(top_builddir)/src/lib/util/libb10-util.la b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la man_MANS = b10-host.1 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-host.xml .PHONY: man diff --git a/src/bin/loadzone/Makefile.am b/src/bin/loadzone/Makefile.am index a37aeb15bd..790f75722f 100644 --- a/src/bin/loadzone/Makefile.am +++ b/src/bin/loadzone/Makefile.am @@ -5,7 +5,7 @@ noinst_SCRIPTS = run_loadzone.sh CLEANFILES = b10-loadzone man_MANS = b10-loadzone.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-loadzone.xml if GENERATE_DOCS diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am index 5b981c4f61..4244d07c42 100644 --- a/src/bin/msgq/Makefile.am +++ b/src/bin/msgq/Makefile.am @@ -7,7 +7,7 @@ pkglibexec_SCRIPTS = b10-msgq CLEANFILES = b10-msgq msgq.pyc man_MANS = b10-msgq.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) msgq.xml if GENERATE_DOCS diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am index 7c1c849879..47e242c1b4 100644 --- a/src/bin/resolver/Makefile.am +++ b/src/bin/resolver/Makefile.am @@ -23,7 +23,7 @@ CLEANFILES += resolver.spec spec_config.h CLEANFILES += resolver_messages.cc resolver_messages.h man_MANS = b10-resolver.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-resolver.xml resolver_messages.mes if GENERATE_DOCS diff --git a/src/bin/sockcreator/Makefile.am b/src/bin/sockcreator/Makefile.am index 966d449965..4e66eb7154 100644 --- a/src/bin/sockcreator/Makefile.am +++ b/src/bin/sockcreator/Makefile.am @@ -13,7 +13,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@ CLEANFILES = *.gcno *.gcda man_MANS = b10-sockcreator.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-sockcreator.xml if GENERATE_DOCS diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am index 0e2c3f6080..ef678d4181 100644 --- a/src/bin/stats/Makefile.am +++ b/src/bin/stats/Makefile.am @@ -20,7 +20,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/stats_httpd_messages.pyc man_MANS = b10-stats.8 b10-stats-httpd.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-stats.xml b10-stats-httpd.xml EXTRA_DIST += stats.spec stats-httpd.spec EXTRA_DIST += stats-httpd-xml.tpl stats-httpd-xsd.tpl stats-httpd-xsl.tpl diff --git a/src/bin/sysinfo/Makefile.am b/src/bin/sysinfo/Makefile.am index 2329b0c9b4..25a3556b09 100644 --- a/src/bin/sysinfo/Makefile.am +++ b/src/bin/sysinfo/Makefile.am @@ -12,7 +12,7 @@ MAN1_FILES = \ man_MANS = \ $(MAN1_FILES:.xml=.1) -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) if GENERATE_DOCS diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am index 0dde3c0bfa..ce7977f94e 100644 --- a/src/bin/usermgr/Makefile.am +++ b/src/bin/usermgr/Makefile.am @@ -5,7 +5,7 @@ b10_cmdctl_usermgrdir = $(pkgdatadir) CLEANFILES= b10-cmdctl-usermgr man_MANS = b10-cmdctl-usermgr.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-cmdctl-usermgr.xml if GENERATE_DOCS diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am index cbe3bddb5c..d68f1f9adf 100644 --- a/src/bin/xfrin/Makefile.am +++ b/src/bin/xfrin/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.pyc man_MANS = b10-xfrin.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrin.xml EXTRA_DIST += xfrin.spec xfrin_messages.mes diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am index 87d926ce28..b612e35c09 100644 --- a/src/bin/xfrout/Makefile.am +++ b/src/bin/xfrout/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrout_messages.pyc man_MANS = b10-xfrout.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-xfrout.xml xfrout_messages.mes if GENERATE_DOCS diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am index 58a0fff90c..6dbec03879 100644 --- a/src/bin/zonemgr/Makefile.am +++ b/src/bin/zonemgr/Makefile.am @@ -15,7 +15,7 @@ CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.py CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/zonemgr_messages.pyc man_MANS = b10-zonemgr.8 -MAINTAINERCLEANFILES = $(man_MANS) +DISTCLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) b10-zonemgr.xml zonemgr_messages.mes if GENERATE_DOCS From 9514bc87016b23bb56f615bc2dcb5f8d8f778a51 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Mon, 3 Sep 2012 12:02:43 +0200 Subject: [PATCH 088/148] [2160] remove superfluous call to message->clear() --- src/lib/asiodns/sync_udp_server.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/asiodns/sync_udp_server.cc b/src/lib/asiodns/sync_udp_server.cc index a31301d0df..037074a1c1 100644 --- a/src/lib/asiodns/sync_udp_server.cc +++ b/src/lib/asiodns/sync_udp_server.cc @@ -116,7 +116,6 @@ SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) { // Make sure the buffers are fresh output_buffer_->clear(); - query_->clear(isc::dns::Message::PARSE); answer_->clear(isc::dns::Message::RENDER); // Mark that we don't have an answer yet. From 6ca3dadca8255b8bb2aa58421f3f4289efe4e63a Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Mon, 3 Sep 2012 14:15:22 +0200 Subject: [PATCH 089/148] [1959] Implemented first set of changes from the code review. --- src/lib/dhcp/iface_mgr.cc | 1 - src/lib/dhcp/iface_mgr.h | 4 +- src/lib/dhcp/libdhcp++.cc | 2 +- src/lib/dhcp/libdhcp++.h | 1 - src/lib/dhcp/option.h | 1 - src/lib/dhcp/tests/iface_mgr_unittest.cc | 98 ++++++++++++++++++++++++ src/lib/dhcp/tests/libdhcp++_unittest.cc | 34 ++++++-- 7 files changed, 131 insertions(+), 10 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 5f78653614..54db434d8f 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -70,7 +70,6 @@ void IfaceMgr::Iface::closeSockets() { for (SocketCollection::iterator sock = sockets_.begin(); sock != sockets_.end(); ++sock) { - cout << "Closing socket " << sock->sockfd_ << endl; close(sock->sockfd_); } sockets_.clear(); diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index 03ccf2426a..178d24a9ec 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -89,7 +89,7 @@ public: /// @param ifindex interface index (unique integer identifier) Iface(const std::string& name, int ifindex); - /// @brief Closes all open sockets on interface + /// @brief Closes all open sockets on interface. void closeSockets(); /// @brief Returns full interface name as "ifname/ifindex" string. @@ -204,6 +204,8 @@ public: /// in this collection. Note that functions like /// @ref IfaceMgr::openSocketFromIface use /// @ref IfaceMgr::openSocket internally. + /// The returned reference is only valid during the lifetime of + /// the IfaceMgr object that returned it. /// /// @return collection of sockets added to interface const SocketCollection& getSockets() const { return sockets_; } diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc index 4ff07eac6a..22cd47bb6e 100644 --- a/src/lib/dhcp/libdhcp++.cc +++ b/src/lib/dhcp/libdhcp++.cc @@ -56,7 +56,7 @@ LibDHCP::optionFactory(Option::Universe u, isc_throw(BadValue, "invalid universe specified (expected " "Option::V4 or Option::V6"); } - return(it->second(u, type, buf)); + return (it->second(u, type, buf)); } diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h index c959609c61..ae907012cc 100644 --- a/src/lib/dhcp/libdhcp++.h +++ b/src/lib/dhcp/libdhcp++.h @@ -45,7 +45,6 @@ public: uint16_t type, const OptionBuffer& buf); - /// Builds collection of options. /// /// Builds raw (on-wire) data for provided collection of options. diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h index 37069d6df5..9589c37ab9 100644 --- a/src/lib/dhcp/option.h +++ b/src/lib/dhcp/option.h @@ -99,7 +99,6 @@ public: return factory(u, type, OptionBuffer()); } - /// @brief ctor, used for options constructed, usually during transmission /// /// @param u option universe (DHCPv4 or DHCPv6) diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 5562551a0e..7f8555c1fa 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -59,6 +59,7 @@ public: ~IfaceMgrTest() { } + }; // We need some known interface to work reliably. Loopback interface @@ -217,6 +218,94 @@ TEST_F(IfaceMgrTest, getIface) { } +TEST_F(IfaceMgrTest, multipleSockets) { + boost::scoped_ptr ifacemgr(new NakedIfaceMgr()); + + // container for initialized socket descriptors + std::list init_sockets; + + // create socket #1 + int socket1 = 0; + ASSERT_NO_THROW( + socket1 = ifacemgr->openSocketFromIface(LOOPBACK, PORT1, AF_INET); + ); + ASSERT_GT(socket1, 0); + init_sockets.push_back(socket1); + + // create socket #2 + IOAddress loAddr("127.0.0.1"); + int socket2 = 0; + ASSERT_NO_THROW( + socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2); + ); + ASSERT_GT(socket2, 0); + init_sockets.push_back(socket2); + + // Get loopback interface. If we don't find one we are unable to run + // this test but we don't want to fail. + IfaceMgr::Iface* iface_ptr = ifacemgr->getIface(LOOPBACK); + if (iface_ptr == NULL) { + cout << "Local loopback interface not found. Skipping test. " << endl; + return; + } + // Once sockets have been sucessfully opened, they are supposed to + // be on the list. Here we start to test if all expected sockets + // are on the list and no other (unexpected) socket is there. + IfaceMgr::SocketCollection sockets = iface_ptr->getSockets(); + int matched_sockets = 0; + for (std::list::iterator init_sockets_it = + init_sockets.begin(); + init_sockets_it != init_sockets.end(); ++init_sockets_it) { + // Set socket descriptors non blocking in order to be able + // to call recv() on them without hang. + int flags = fcntl(*init_sockets_it, F_GETFL, 0); + ASSERT_GE(flags, 0); + ASSERT_GE(fcntl(*init_sockets_it, F_SETFL, flags | O_NONBLOCK), 0); + // recv() is expected to result in EWOULDBLOCK error on non-blocking + // socket in case socket is valid but simply no data are coming in. + char buf; + recv(*init_sockets_it, &buf, 1, MSG_PEEK); + EXPECT_EQ(EWOULDBLOCK, errno); + // Apart from the ability to use the socket we want to make + // sure that socket on the list is the one that we created. + for (IfaceMgr::SocketCollection::const_iterator socket_it = + sockets.begin(); socket_it != sockets.end(); ++socket_it) { + if (*init_sockets_it == socket_it->sockfd_) { + // This socket is the one that we created. + ++matched_sockets; + break; + } + } + } + // all created sockets have been matched if this condition works. + EXPECT_EQ(sockets.size(), matched_sockets); + + // closeSockets() is the other function that we want to test. It + // is supposed to close all sockets so as we will not be able to use + // them anymore communication. + ifacemgr->closeSockets(); + + // closed sockets are supposed to be removed from the list + sockets = iface_ptr->getSockets(); + ASSERT_EQ(0, sockets.size()); + + // We are still in posession of socket descriptors that we created + // on the beginning of this test. We can use them to check whether + // closeSockets() only removed them from the list or they have been + // really closed. + for (std::list::const_iterator init_sockets_it = + init_sockets.begin(); + init_sockets_it != init_sockets.end(); ++init_sockets_it) { + // recv() must result in error when using invalid socket. + char buf; + recv(*init_sockets_it, &buf, 1, MSG_PEEK); + // EWOULDBLOCK would mean that socket is valid/open but + // simply no data is received so we have to check for + // other errors. + EXPECT_NE(EWOULDBLOCK, errno); + } +} + TEST_F(IfaceMgrTest, sockets6) { // testing socket operation in a portable way is tricky // without interface detection implemented @@ -317,6 +406,15 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) { ); EXPECT_GT(socket2, 0); close(socket2); + + // Open v4 socket to connect to broadcast address. + int socket3 = 0; + IOAddress bcastAddr("255.255.255.255"); + EXPECT_NO_THROW( + socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2); + ); + EXPECT_GT(socket3, 0); + close(socket3); } // TODO: disabled due to other naming on various systems diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index ac758bed9c..d17eb6537f 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -87,21 +87,45 @@ TEST(LibDhcpTest, optionFactory) { DHO_SUBNET_MASK, buf); // Check if non-NULL DHO_SUBNET_MASK option pointer has been returned. - EXPECT_TRUE(opt_subnet_mask); + ASSERT_TRUE(opt_subnet_mask); + // Validate if type and universe is correct. + EXPECT_EQ(Option::V4, opt_subnet_mask->getUniverse()); + EXPECT_EQ(DHO_SUBNET_MASK, opt_subnet_mask->getType()); + // Expect that option does not have content.. + EXPECT_EQ(0, opt_subnet_mask->len() - opt_subnet_mask->getHeaderLen()); + // Fill the time offset buffer with 4 bytes of data. Each byte set to 1. + OptionBuffer time_offset_buf(4, 1); OptionPtr opt_time_offset; opt_time_offset = LibDHCP::optionFactory(Option::V4, DHO_TIME_OFFSET, - buf); + time_offset_buf); // Check if non-NULL DHO_TIME_OFFSET option pointer has been returned. - EXPECT_TRUE(opt_time_offset); + ASSERT_TRUE(opt_time_offset); + // Validate if option length, type and universe is correct. + EXPECT_EQ(Option::V4, opt_time_offset->getUniverse()); + EXPECT_EQ(DHO_TIME_OFFSET, opt_time_offset->getType()); + EXPECT_EQ(time_offset_buf.size(), + opt_time_offset->len() - opt_time_offset->getHeaderLen()); + // Validate data in the option. + EXPECT_TRUE(std::equal(time_offset_buf.begin(), time_offset_buf.end(), + opt_time_offset->getData().begin())); + // Fill the client id buffer with 20 bytes of data. Each byte set to 2. + OptionBuffer clientid_buf(20, 2); OptionPtr opt_clientid; opt_clientid = LibDHCP::optionFactory(Option::V6, D6O_CLIENTID, - buf); + clientid_buf); // Check if non-NULL D6O_CLIENTID option pointer has been returned. - EXPECT_TRUE(opt_clientid); + ASSERT_TRUE(opt_clientid); + // Validate if option length, type and universe is correct. + EXPECT_EQ(Option::V6, opt_clientid->getUniverse()); + EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType()); + EXPECT_EQ(clientid_buf.size(), opt_clientid->len() - opt_clientid->getHeaderLen()); + // Validate data in the option. + EXPECT_TRUE(std::equal(clientid_buf.begin(), clientid_buf.end(), + opt_clientid->getData().begin())); } TEST(LibDhcpTest, packOptions6) { From 83a400743d99693d21fe04636c4958c3d82399f8 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Mon, 3 Sep 2012 21:54:27 +0900 Subject: [PATCH 090/148] [2098] made TreeNodeRRset non-copyable explicitly and documented it. --- src/lib/datasrc/memory/treenode_rrset.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h index 2ad3a3c289..dd94245049 100644 --- a/src/lib/datasrc/memory/treenode_rrset.h +++ b/src/lib/datasrc/memory/treenode_rrset.h @@ -28,6 +28,8 @@ #include #include +#include + #include namespace isc { @@ -65,12 +67,17 @@ namespace memory { /// it should be safe, but we should eventually provide complete /// implementations of these methods. /// +/// This class can internally maintain dynamically allocated resource. +/// It would cause copying a class object complicated while objects of +/// this class are not expected to be copyable in the usage, so it's +/// explicitly defined non copyable. +/// /// \note This class is exposed in this separate header file so that other /// part of the in-memory data source implementation and test code /// can refer to its definition, and only for that purpose. Otherwise this is /// essentially a private class of the in-memory data source implementation, /// and an application shouldn't directly refer to this class. -class TreeNodeRRset : public dns::AbstractRRset { +class TreeNodeRRset : boost::noncopyable, public dns::AbstractRRset { public: /// \brief Normal case constructor. /// From 26c61ea85a87cdc20ae9b52801b84338a4f0bbf2 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Mon, 3 Sep 2012 23:09:43 +0900 Subject: [PATCH 091/148] [master] worked around dubious compiler behavior on const reference this workaround should avoid this build error: http://git.bind10.isc.org/~tester/builder//BIND10/20120903130000-FreeBSD8-i386-Clang/logs/build.out --- .../memory/tests/treenode_rrset_unittest.cc | 108 +++++++++++------- 1 file changed, 65 insertions(+), 43 deletions(-) diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc index b95e706b42..41f369079f 100644 --- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc +++ b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc @@ -25,6 +25,8 @@ #include +#include + #include #include @@ -150,33 +152,53 @@ checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name, EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount()); } +// The following two are trivial wrapper to create a shared pointer +// version of TreeNodeRRset object in order to work around dubious +// behavior of some C++ compiler: they reject getting a const reference to +// a temporary non-copyable object. +boost::shared_ptr +createRRset(const RRClass& rrclass, const ZoneNode* node, + const RdataSet* rdataset, bool dnssec_ok) +{ + return (boost::shared_ptr( + new TreeNodeRRset(rrclass, node, rdataset, dnssec_ok))); +} + +boost::shared_ptr +createRRset(const Name& realname, const RRClass& rrclass, const ZoneNode* node, + const RdataSet* rdataset, bool dnssec_ok) +{ + return (boost::shared_ptr( + new TreeNodeRRset(realname, rrclass, node, rdataset, + dnssec_ok))); +} + TEST_F(TreeNodeRRsetTest, create) { // Constructed with RRSIG, and it should be visible. - checkBasicFields(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true), + checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true), www_name_, rrclass_, RRType::A(), 2, 1); // Constructed with RRSIG, and it should be invisible. - checkBasicFields(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false), + checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, false), www_name_, rrclass_, RRType::A(), 2, 0); // Constructed without RRSIG, and it would be visible (but of course won't) - checkBasicFields(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_, true), + checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, true), origin_name_, rrclass_, RRType::NS(), 1, 0); // Constructed without RRSIG, and it should be visible - checkBasicFields(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_, - false), + checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, false), origin_name_, rrclass_, RRType::NS(), 1, 0); // RRSIG-only case (note the RRset's type is covered type) - checkBasicFields(TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_, - true), + checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_, + true), www_name_, rrclass_, RRType::TXT(), 0, 1); // RRSIG-only case (note the RRset's type is covered type), but it's // invisible - checkBasicFields(TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_, - false), + checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_, + false), www_name_, rrclass_, RRType::TXT(), 0, 0); // Wildcard substitution - checkBasicFields(TreeNodeRRset(match_name_, rrclass_, - wildcard_node_, wildcard_rdataset_, - true), + checkBasicFields(*createRRset(match_name_, rrclass_, + wildcard_node_, wildcard_rdataset_, + true), match_name_, rrclass_, RRType::A(), 2, 1); } @@ -307,8 +329,8 @@ TEST_F(TreeNodeRRsetTest, toWire) { { SCOPED_TRACE("wildcard with RRSIG"); checkToWireResult(expected_renderer, actual_renderer, - TreeNodeRRset(match_name_, rrclass_, wildcard_node_, - wildcard_rdataset_, true), + *createRRset(match_name_, rrclass_, wildcard_node_, + wildcard_rdataset_, true), origin_name_, wildmatch_rrset_, wildmatch_rrsig_rrset_, true); } @@ -316,8 +338,8 @@ TEST_F(TreeNodeRRsetTest, toWire) { { SCOPED_TRACE("wildcard without RRSIG"); checkToWireResult(expected_renderer, actual_renderer, - TreeNodeRRset(match_name_, rrclass_, wildcard_node_, - wildcard_rdataset_, false), + *createRRset(match_name_, rrclass_, wildcard_node_, + wildcard_rdataset_, false), origin_name_, wildmatch_rrset_, wildmatch_rrsig_rrset_, false); } @@ -355,7 +377,7 @@ TEST_F(TreeNodeRRsetTest, toWireTruncated) { // (type, class, TTL, rdlen, and 4-byte IPv4 address). Then we can only // render just one RR, without any garbage trailing data. checkToWireResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true), + *createRRset(rrclass_, www_node_, a_rdataset_, true), name, a_rrset_, a_rrsig_rrset_, true, www_name_.getLength() + 14, 1); // 1 main RR, no RRSIG @@ -363,7 +385,7 @@ TEST_F(TreeNodeRRsetTest, toWireTruncated) { // The first main RRs should fit in the renderer (the name will be // fully compressed, so its size is 2 bytes), but the RRSIG doesn't. checkToWireResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true), + *createRRset(rrclass_, www_node_, a_rdataset_, true), name, a_rrset_, a_rrsig_rrset_, true, www_name_.getLength() + 14 + 2 + 14, 2); // 2 main RR, no RRSIG @@ -379,15 +401,15 @@ TEST_F(TreeNodeRRsetTest, toWireTruncated) { const size_t limit_len = expected_renderer.getLength(); // Then perform the test checkToWireResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, aaaa_rdataset_, true), + *createRRset(rrclass_, www_node_, aaaa_rdataset_, true), name, aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len, 2); // 1 main RR, 1 RRSIG // RRSIG only case. Render length limit being 1, so it won't fit, // and will cause truncation. checkToWireResult(expected_renderer, actual_renderer, - TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_, - true), + *createRRset(rrclass_, www_node_, rrsig_only_rdataset_, + true), name, ConstRRsetPtr(), txt_rrsig_rrset_, true, 1, 0); // no RR } @@ -455,32 +477,32 @@ checkToText(const AbstractRRset& actual_rrset, TEST_F(TreeNodeRRsetTest, toText) { // Constructed with RRSIG, and it should be visible. - checkToText(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true), + checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, true), a_rrset_, a_rrsig_rrset_); // Constructed with RRSIG, and it should be invisible. - checkToText(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false), + checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, false), a_rrset_, ConstRRsetPtr()); // Constructed without RRSIG, and it would be visible (but of course won't) - checkToText(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_, true), + checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, true), ns_rrset_, ConstRRsetPtr()); // Constructed without RRSIG, and it should be visible - checkToText(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_, false), + checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, false), ns_rrset_, ConstRRsetPtr()); // Wildcard expanded name with RRSIG - checkToText(TreeNodeRRset(match_name_, rrclass_, wildcard_node_, - wildcard_rdataset_, true), + checkToText(*createRRset(match_name_, rrclass_, wildcard_node_, + wildcard_rdataset_, true), wildmatch_rrset_, wildmatch_rrsig_rrset_); // Wildcard expanded name without RRSIG - checkToText(TreeNodeRRset(match_name_, rrclass_, wildcard_node_, - wildcard_rdataset_, false), + checkToText(*createRRset(match_name_, rrclass_, wildcard_node_, + wildcard_rdataset_, false), wildmatch_rrset_, ConstRRsetPtr()); // RRSIG case - checkToText(TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_, - true), + checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_, + true), ConstRRsetPtr(), txt_rrsig_rrset_); // Similar to the previous case, but completely empty. - checkToText(TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_, - false), + checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_, + false), ConstRRsetPtr(), ConstRRsetPtr()); } @@ -488,22 +510,22 @@ TEST_F(TreeNodeRRsetTest, isSameKind) { const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true); // Same name (node), same type (rdataset) => same kind - EXPECT_TRUE(rrset.isSameKind(TreeNodeRRset(rrclass_, www_node_, - a_rdataset_, true))); + EXPECT_TRUE(rrset.isSameKind(*createRRset(rrclass_, www_node_, + a_rdataset_, true))); // Same name (node), different type (rdataset) => not same kind - EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, www_node_, - aaaa_rdataset_, true))); + EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, www_node_, + aaaa_rdataset_, true))); // Different name, different type => not same kind - EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, origin_node_, - ns_rdataset_, true))); + EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_, + ns_rdataset_, true))); // Different name, same type => not same kind. // Note: this shouldn't happen in our in-memory data source implementation, // but API doesn't prohibit it. - EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, origin_node_, - a_rdataset_, true))); + EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_, + a_rdataset_, true))); // Wildcard and expanded RRset const TreeNodeRRset wildcard_rrset(rrclass_, wildcard_node_, @@ -535,8 +557,8 @@ TEST_F(TreeNodeRRsetTest, isSameKind) { // tree node, they must belong to the same RR class. This case is // a caller's bug, and the isSameKind() implementation returns the // "wrong" (= true) answer. - EXPECT_TRUE(rrset.isSameKind(TreeNodeRRset(RRClass::CH(), www_node_, - a_rdataset_, true))); + EXPECT_TRUE(rrset.isSameKind(*createRRset(RRClass::CH(), www_node_, + a_rdataset_, true))); // Same kind of different RRset class EXPECT_TRUE(rrset.isSameKind(*a_rrset_)); From c9ee1db8c6acdd3af040168229729124c619cef9 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Tue, 4 Sep 2012 09:37:57 +0200 Subject: [PATCH 092/148] [master] update Changelog for merge of #357 --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index af508216f1..da4a82666a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +473. [bug] jelte + TCP connections now time out in b10-auth if no (or not all) query + data is sent by the client. The timeout value defaults to 5000 + milliseconds, but is configurable in Auth/tcp_recv_timeout. + (Trac #357, git cdf3f04442f8f131542bd1d4a2228a9d0bed12ff) + 472. [build] jreed All generated documentation is removed from the git repository. The ./configure --enable-man option is removed. A new option From 34955bf9d032356233d00347d35e4cb2af07cdb4 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Tue, 4 Sep 2012 10:17:27 +0200 Subject: [PATCH 093/148] [master] add libdeps to datasrc/memory/benchmarks --- src/lib/datasrc/memory/benchmarks/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/datasrc/memory/benchmarks/Makefile.am b/src/lib/datasrc/memory/benchmarks/Makefile.am index 3328699fb3..9ed18af76d 100644 --- a/src/lib/datasrc/memory/benchmarks/Makefile.am +++ b/src/lib/datasrc/memory/benchmarks/Makefile.am @@ -14,8 +14,11 @@ noinst_PROGRAMS = rdata_reader_bench rrset_render_bench rdata_reader_bench_SOURCES = rdata_reader_bench.cc rdata_reader_bench_LDADD = $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la rdata_reader_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la +rdata_reader_bench_LDADD += $(top_builddir)/src/lib/util/libb10-util.la rdata_reader_bench_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la rrset_render_bench_SOURCES = rrset_render_bench.cc rrset_render_bench_LDADD = $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la +rrset_render_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la +rrset_render_bench_LDADD += $(top_builddir)/src/lib/util/libb10-util.la rrset_render_bench_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la From 6a3c2c618081b259a7eef9f747b1e6cc8aea4572 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 4 Sep 2012 10:25:00 +0200 Subject: [PATCH 094/148] [1959] Implemented changes from the second part of code review. --- tests/tools/perfdhcp/command_options.cc | 55 ++-- tests/tools/perfdhcp/command_options.h | 237 +++++++++--------- tests/tools/perfdhcp/localized_option.h | 89 +++---- tests/tools/perfdhcp/perf_pkt4.h | 1 - tests/tools/perfdhcp/pkt_transform.cc | 7 +- tests/tools/perfdhcp/pkt_transform.h | 2 +- tests/tools/perfdhcp/stats_mgr.h | 9 +- tests/tools/perfdhcp/test_control.cc | 18 +- tests/tools/perfdhcp/test_control.h | 4 +- .../tests/command_options_unittest.cc | 29 ++- .../perfdhcp/tests/perf_pkt4_unittest.cc | 46 ++++ .../perfdhcp/tests/test_control_unittest.cc | 6 +- 12 files changed, 274 insertions(+), 229 deletions(-) diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index fcdb7bd484..dbb01e7d4c 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -56,8 +56,8 @@ CommandOptions::reset() { rate_ = 0; report_delay_ = 0; clients_num_ = 0; - mac_prefix_.assign(mac, mac + 6); - duid_prefix_.clear(); + mac_template_.assign(mac, mac + 6); + duid_template_.clear(); base_.clear(); num_request_.clear(); period_ = 0; @@ -84,8 +84,8 @@ CommandOptions::reset() { diags_.clear(); wrapped_.clear(); server_name_.clear(); - - generateDuidPrefix(); + generateDuidTemplate(); + commandline_.clear(); } void @@ -132,9 +132,16 @@ CommandOptions::initialize(int argc, char** argv) { int offset_arg = 0; // Temporary variable holding offset arguments std::string sarg; // Temporary variable for string args + std::ostringstream stream; + stream << "perfdhcp"; + // In this section we collect argument values from command line // they will be tuned and validated elsewhere while((opt = getopt(argc, argv, "hv46r:t:R:b:n:p:d:D:l:P:a:L:s:iBc1T:X:O:E:S:I:x:w:")) != -1) { + stream << " -" << opt; + if (optarg) { + stream << " " << optarg; + } switch (opt) { case 'v': version(); @@ -318,6 +325,8 @@ CommandOptions::initialize(int argc, char** argv) { } } + std::cout << "Running: " << stream.str() << std::endl; + // If the IP version was not specified in the // command line, assume IPv4. if (ipversion_ == 0) { @@ -375,8 +384,8 @@ CommandOptions::initialize(int argc, char** argv) { // If DUID is not specified from command line we need to // generate one. - if (duid_prefix_.size() == 0) { - generateDuidPrefix(); + if (duid_template_.size() == 0) { + generateDuidTemplate(); } } @@ -439,7 +448,7 @@ CommandOptions::decodeMac(const std::string& base) { // Decode mac address to vector of uint8_t std::istringstream s1(base.substr(found + 1)); std::string token; - mac_prefix_.clear(); + mac_template_.clear(); // Get pieces of MAC address separated with : (or even ::) while (std::getline(s1, token, ':')) { unsigned int ui = 0; @@ -454,17 +463,17 @@ CommandOptions::decodeMac(const std::string& base) { } // If conversion succeeded store byte value - mac_prefix_.push_back(ui); + mac_template_.push_back(ui); } } // MAC address must consist of 6 octets, otherwise it is invalid - check(mac_prefix_.size() != 6, errmsg); + check(mac_template_.size() != 6, errmsg); } void CommandOptions::decodeDuid(const std::string& base) { // Strip argument from duid= - std::vector duid_prefix; + std::vector duid_template; size_t found = base.find('='); check(found == std::string::npos, "expected -b format for duid is -b duid="); std::string b = base.substr(found + 1); @@ -484,26 +493,26 @@ CommandOptions::decodeDuid(const std::string& base) { isc_throw(isc::InvalidParameter, "invalid characters in DUID provided, exepected hex digits"); } - duid_prefix.push_back(static_cast(ui)); + duid_template.push_back(static_cast(ui)); } // Assign the new duid only if successfully generated. - std::swap(duid_prefix, duid_prefix_); + std::swap(duid_template, duid_template_); } void -CommandOptions::generateDuidPrefix() { +CommandOptions::generateDuidTemplate() { using namespace boost::posix_time; - // Duid prefix will be most likely generated only once but + // Duid template will be most likely generated only once but // it is ok if it is called more then once so we simply // regenerate it and discard previous value. - duid_prefix_.clear(); - const uint8_t duid_prefix_len = 14; - duid_prefix_.resize(duid_prefix_len); + duid_template_.clear(); + const uint8_t duid_template_len = 14; + duid_template_.resize(duid_template_len); // The first four octets consist of DUID LLT and hardware type. - duid_prefix_[0] = DUID_LLT >> 8; - duid_prefix_[1] = DUID_LLT & 0xff; - duid_prefix_[2] = HWTYPE_ETHERNET >> 8; - duid_prefix_[3] = HWTYPE_ETHERNET & 0xff; + duid_template_[0] = DUID_LLT >> 8; + duid_template_[1] = DUID_LLT & 0xff; + duid_template_[2] = HWTYPE_ETHERNET >> 8; + duid_template_[3] = HWTYPE_ETHERNET & 0xff; // As described in RFC3315: 'the time value is the time // that the DUID is generated represented in seconds @@ -512,12 +521,12 @@ CommandOptions::generateDuidPrefix() { ptime duid_epoch(from_iso_string("20000101T000000")); time_period period(duid_epoch, now); uint32_t duration_sec = htonl(period.length().total_seconds()); - memcpy(&duid_prefix_[4], &duration_sec, 4); + memcpy(&duid_template_[4], &duration_sec, 4); // Set link layer address (6 octets). This value may be // randomized before sending a packet to simulate different // clients. - memcpy(&duid_prefix_[8], &mac_prefix_[0], 6); + memcpy(&duid_template_[8], &mac_template_[0], 6); } uint8_t diff --git a/tests/tools/perfdhcp/command_options.h b/tests/tools/perfdhcp/command_options.h index b9f2c3a198..b9e2b9e70e 100644 --- a/tests/tools/perfdhcp/command_options.h +++ b/tests/tools/perfdhcp/command_options.h @@ -23,7 +23,7 @@ namespace isc { namespace perfdhcp { -/// \brief Command Options +/// \brief Command Options. /// /// This class is responsible for parsing the command-line and storing the /// specified options. @@ -49,64 +49,64 @@ public: /// command line options. void reset(); - /// \brief Parse command line + /// \brief Parse command line. /// /// Parses the command line and stores the selected options /// in class data members. /// /// \param argc Argument count passed to main(). /// \param argv Argument value array passed to main(). - /// \throws isc::InvalidParameter if parse fails + /// \throws isc::InvalidParameter if parse fails. void parse(int argc, char** const argv); - /// \brief Returns IP version + /// \brief Returns IP version. /// - /// \return IP version to be used + /// \return IP version to be used. uint8_t getIpVersion() const { return ipversion_; } - /// \brief Returns packet exchange mode + /// \brief Returns packet exchange mode. /// - /// \return packet exchange mode + /// \return packet exchange mode. ExchangeMode getExchangeMode() const { return exchange_mode_; } - /// \brief Returns echange rate + /// \brief Returns echange rate. /// - /// \return exchange rate per second + /// \return exchange rate per second. int getRate() const { return rate_; } - /// \brief Returns delay between two performance reports + /// \brief Returns delay between two performance reports. /// - /// \return delay between two consecutive performance reports + /// \return delay between two consecutive performance reports. int getReportDelay() const { return report_delay_; } - /// \brief Returns number of simulated clients + /// \brief Returns number of simulated clients. /// - /// \return number of simulated clients + /// \return number of simulated clients. uint32_t getClientsNum() const { return clients_num_; } - /// \brief Returns MAC address prefix + /// \brief Returns MAC address template. /// - /// \ return MAC address prefix to simulate different clients - std::vector getMacPrefix() const { return mac_prefix_; } + /// \return MAC address template to simulate different clients. + std::vector getMacTemplate() const { return mac_template_; } - /// \brief Returns DUID prefix + /// \brief Returns DUID template. /// - /// \return DUID prefix to simulate different clients - std::vector getDuidPrefix() const { return duid_prefix_; } + /// \return DUID template to simulate different clients. + std::vector getDuidTemplate() const { return duid_template_; } - /// \brief Returns base values + /// \brief Returns base values. /// - /// \return all base values specified + /// \return all base values specified. std::vector getBase() const { return base_; } - /// \brief Returns maximum number of exchanges + /// \brief Returns maximum number of exchanges. /// - /// \return number of exchange requests before test is aborted + /// \return number of exchange requests before test is aborted. std::vector getNumRequests() const { return num_request_; } - /// \brief Returns test period + /// \brief Returns test period. /// - /// \return test period before it is aborted + /// \return test period before it is aborted. int getPeriod() const { return period_; } /// \brief Returns drop time @@ -114,139 +114,139 @@ public: /// The method returns maximum time elapsed from /// sending the packet before it is assumed dropped. /// - /// \return return time before request is assumed dropped + /// \return return time before request is assumed dropped. std::vector getDropTime() const { return drop_time_; } - /// \brief Returns maximum drops number + /// \brief Returns maximum drops number. /// /// Returns maximum number of packet drops before /// aborting a test. /// - /// \return maximum number of dropped requests + /// \return maximum number of dropped requests. std::vector getMaxDrop() const { return max_drop_; } - /// \brief Returns maximal percentage of drops + /// \brief Returns maximal percentage of drops. /// /// Returns maximal percentage of packet drops /// before aborting a test. /// - /// \return maximum percentage of lost requests + /// \return maximum percentage of lost requests. std::vector getMaxDropPercentage() const { return max_pdrop_; } - /// \brief Returns local address or interface name + /// \brief Returns local address or interface name. /// - /// \return local address or interface name + /// \return local address or interface name. std::string getLocalName() const { return localname_; } - /// \brief Checks if interface name was used + /// \brief Checks if interface name was used. /// /// The method checks if interface name was used /// rather than address. /// - /// \return true if interface name was used + /// \return true if interface name was used. bool isInterface() const { return is_interface_; } - /// \brief Returns number of preload exchanges + /// \brief Returns number of preload exchanges. /// - /// \return number of preload exchanges + /// \return number of preload exchanges. int getPreload() const { return preload_; } - /// \brief Returns aggressivity value + /// \brief Returns aggressivity value. /// - /// \return aggressivity value + /// \return aggressivity value. int getAggressivity() const { return aggressivity_; } - /// \brief Returns local port number + /// \brief Returns local port number. /// - /// \return local port number + /// \return local port number. int getLocalPort() const { return local_port_; } - /// \brief Checks if seed provided + /// \brief Checks if seed provided. /// - /// \return true if seed was provided + /// \return true if seed was provided. bool isSeeded() const { return seeded_; } - /// \brief Returns radom seed + /// \brief Returns radom seed. /// - /// \return random seed + /// \return random seed. uint32_t getSeed() const { return seed_; } - /// \brief Checks if broadcast address is to be used + /// \brief Checks if broadcast address is to be used. /// - /// \return true if broadcast address is to be used + /// \return true if broadcast address is to be used. bool isBroadcast() const { return broadcast_; } - /// \brief Check if rapid commit option used + /// \brief Check if rapid commit option used. /// - /// \return true if rapid commit option is used + /// \return true if rapid commit option is used. bool isRapidCommit() const { return rapid_commit_; } - /// \brief Check if server-ID to be taken from first package + /// \brief Check if server-ID to be taken from first package. /// - /// \return true if server-iD to be taken from first package + /// \return true if server-iD to be taken from first package. bool isUseFirst() const { return use_first_; } - /// \brief Returns template file names + /// \brief Returns template file names. /// - /// \return template file names + /// \return template file names. std::vector getTemplateFiles() const { return template_file_; } - /// brief Returns template offsets for xid + /// brief Returns template offsets for xid. /// - /// \return template offsets for xid + /// \return template offsets for xid. std::vector getTransactionIdOffset() const { return xid_offset_; } - /// \brief Returns template offsets for rnd + /// \brief Returns template offsets for rnd. /// - /// \return template offsets for rnd + /// \return template offsets for rnd. std::vector getRandomOffset() const { return rnd_offset_; } - /// \brief Returns template offset for elapsed time + /// \brief Returns template offset for elapsed time. /// - /// \return template offset for elapsed time + /// \return template offset for elapsed time. int getElapsedTimeOffset() const { return elp_offset_; } - /// \brief Returns template offset for server-ID + /// \brief Returns template offset for server-ID. /// - /// \return template offset for server-ID + /// \return template offset for server-ID. int getServerIdOffset() const { return sid_offset_; } - /// \brief Returns template offset for requested IP + /// \brief Returns template offset for requested IP. /// - /// \return template offset for requested IP + /// \return template offset for requested IP. int getRequestedIpOffset() const { return rip_offset_; } - /// \brief Returns diagnostic selectors + /// \brief Returns diagnostic selectors. /// - /// \return diagnostics selector + /// \return diagnostics selector. std::string getDiags() const { return diags_; } - /// \brief Returns wrapped command + /// \brief Returns wrapped command. /// - /// \return wrapped command (start/stop) + /// \return wrapped command (start/stop). std::string getWrapped() const { return wrapped_; } - /// \brief Returns server name + /// \brief Returns server name. /// - /// \return server name + /// \return server name. std::string getServerName() const { return server_name_; } - /// \brief Prints command line arguments. + /// \brief Print command line arguments. void printCommandLine() const; - /// \brief Print usage + /// \brief Print usage. /// - /// Prints perfdhcp usage + /// Prints perfdhcp usage. void usage() const; - /// \brief Print program version + /// \brief Print program version. /// - /// Prints perfdhcp version + /// Prints perfdhcp version. void version() const; private: - /// \brief Default Constructor + /// \brief Default Constructor. /// /// Private constructor as this is a singleton class. /// Use CommandOptions::instance() to get instance of it. @@ -254,54 +254,54 @@ private: reset(); } - /// \brief Initializes class members based command line + /// \brief Initializes class members based on the command line. /// - /// Reads each command line parameter and sets class member values + /// Reads each command line parameter and sets class member values. /// /// \param argc Argument count passed to main(). /// \param argv Argument value array passed to main(). - /// \throws isc::InvalidParameter if command line options initialization fails + /// \throws isc::InvalidParameter if command line options initialization fails. void initialize(int argc, char** argv); - /// \brief Validates initialized options + /// \brief Validates initialized options. /// - /// \throws isc::InvalidParameter if command line validation fails + /// \throws isc::InvalidParameter if command line validation fails. void validate() const; - /// \brief Throws !InvalidParameter exception if condition is true + /// \brief Throws !InvalidParameter exception if condition is true. /// /// Convenience function that throws an InvalidParameter exception if - /// the condition argument is true + /// the condition argument is true. /// - /// \param condition Condition to be checked - /// \param errmsg Error message in exception - /// \throws isc::InvalidParameter if condition argument true + /// \param condition Condition to be checked. + /// \param errmsg Error message in exception. + /// \throws isc::InvalidParameter if condition argument true. inline void check(bool condition, const std::string& errmsg) const; - /// \brief Casts command line argument to positive integer + /// \brief Casts command line argument to positive integer. /// - /// \param errmsg Error message if lexical cast fails - /// \throw InvalidParameter if lexical cast fails + /// \param errmsg Error message if lexical cast fails. + /// \throw InvalidParameter if lexical cast fails. int positiveInteger(const std::string& errmsg) const; - /// \brief Casts command line argument to non-negative integer + /// \brief Casts command line argument to non-negative integer. /// - /// \param errmsg Error message if lexical cast fails - /// \throw InvalidParameter if lexical cast fails + /// \param errmsg Error message if lexical cast fails. + /// \throw InvalidParameter if lexical cast fails. int nonNegativeInteger(const std::string& errmsg) const; - /// \brief Returns command line string if it is not empty + /// \brief Returns command line string if it is not empty. /// - /// \param errmsg Error message if string is empty - /// \throw InvalidParameter if string is empty + /// \param errmsg Error message if string is empty. + /// \throw InvalidParameter if string is empty. std::string nonEmptyString(const std::string& errmsg) const; - /// \brief Set number of clients + /// \brief Set number of clients. /// /// Interprets the getopt() "opt" global variable as the number of clients /// (a non-negative number). This value is specified by the "-R" switch. /// - /// \throw InvalidParameter if -R is wrong + /// \throw InvalidParameter if -R is wrong. void initClientsNum(); /// \brief Sets value indicating if interface name was given. @@ -311,7 +311,7 @@ private: /// is set accordingly. void initIsInterface(); - /// \brief Decodes base provided with -b + /// \brief Decodes base provided with -b. /// /// Function decodes argument of -b switch, which /// specifies a base value used to generate unique @@ -321,45 +321,47 @@ private: /// - -b mac=00:01:02:03:04:05 /// - -b duid=0F1234 (duid can be up to 128 hex digits) // Function will decode 00:01:02:03:04:05 and/or - /// 0F1234 respectively and initialize mac_prefix_ - /// and/or duid_prefix_ members + /// 0F1234 respectively and initialize mac_template_ + /// and/or duid_template_ members. /// - /// \param base Base in string format - /// \throws isc::InvalidParameter if base is invalid + /// \param base Base in string format. + /// \throws isc::InvalidParameter if base is invalid. void decodeBase(const std::string& base); - /// \brief Decodes base MAC address provided with -b + /// \brief Decodes base MAC address provided with -b. /// /// Function decodes parameter given as -b mac=00:01:02:03:04:05 - /// The function will decode 00:01:02:03:04:05 initialize mac_prefix_ + /// The function will decode 00:01:02:03:04:05 initialize mac_template_ /// class member. - /// Provided MAC address is for example only + /// Provided MAC address is for example only. /// - /// \param base Base string given as -b mac=00:01:02:03:04:05 - /// \throws isc::InvalidParameter if mac address is invalid + /// \param base Base string given as -b mac=00:01:02:03:04:05. + /// \throws isc::InvalidParameter if mac address is invalid. void decodeMac(const std::string& base); - /// \brief Decodes base DUID provided with -b + /// \brief Decodes base DUID provided with -b. /// - /// Function decodes parameter given as -b duid=0F1234 - /// The function will decode 0F1234 and initialize duid_prefix_ + /// Function decodes parameter given as -b duid=0F1234. + /// The function will decode 0F1234 and initialize duid_template_ /// class member. /// Provided DUID is for example only. /// - /// \param base Base string given as -b duid=0F1234 - /// \throws isc::InvalidParameter if DUID is invalid + /// \param base Base string given as -b duid=0F1234. + /// \throws isc::InvalidParameter if DUID is invalid. void decodeDuid(const std::string& base); /// \brief Generates DUID-LLT (based on link layer address). /// /// Function generates DUID based on link layer address and - /// initiates duid_prefix_ value with it. - void generateDuidPrefix(); + /// initiates duid_template_ value with it. + /// \todo add support to generate DUIDs other than based on + /// 6-octets long MACs (e.g. DUID-UUID. + void generateDuidTemplate(); - /// \brief Converts two-digit hexadecimal string to a byte + /// \brief Converts two-digit hexadecimal string to a byte. /// - /// \param hex_text Hexadecimal string e.g. AF - /// \throw isc::InvalidParameter if string does not represent hex byte + /// \param hex_text Hexadecimal string e.g. AF. + /// \throw isc::InvalidParameter if string does not represent hex byte. uint8_t convertHexString(const std::string& hex_text) const; uint8_t ipversion_; ///< IP protocol version to be used, expected values are: @@ -369,9 +371,9 @@ private: int report_delay_; ///< Delay between generation of two consecutive ///< performance reports uint32_t clients_num_; ///< Number of simulated clients (aka randomization range). - std::vector mac_prefix_; ///< MAC address prefix used to generate unique DUIDs + std::vector mac_template_; ///< MAC address template used to generate unique DUIDs ///< for simulated clients. - std::vector duid_prefix_; ///< DUID prefix used to generate unique DUIDs for + std::vector duid_template_; ///< DUID template used to generate unique DUIDs for ///< simulated clients std::vector base_; ///< Collection of base values specified with -b ///< options. Supported "bases" are mac= and duid= @@ -420,6 +422,7 @@ private: std::string wrapped_; ///< Wrapped command specified as -w. Expected ///< values are start and stop. std::string server_name_; ///< Server name specified as last argument of command line. + std::string commandline_; ///< Entire command line as typed in by the user. }; } // namespace perfdhcp diff --git a/tests/tools/perfdhcp/localized_option.h b/tests/tools/perfdhcp/localized_option.h index f93089fbad..336e08366e 100644 --- a/tests/tools/perfdhcp/localized_option.h +++ b/tests/tools/perfdhcp/localized_option.h @@ -44,33 +44,46 @@ namespace perfdhcp { /// class LocalizedOption : public dhcp::Option { public: - /// \brief Constructor, sets default (0) option offset - /// - /// \param u specifies universe (V4 or V6) - /// \param type option type (0-255 for V4 and 0-65535 for V6) - /// \param data content of the option - LocalizedOption(dhcp::Option::Universe u, - uint16_t type, - const dhcp::OptionBuffer& data) : - dhcp::Option(u, type, data), - offset_(0), option_valid_(true) { - } - - /// \brief Constructor, used to create localized option from buffer + /// \brief Constructor, used to create localized option from buffer. /// - /// \param u specifies universe (V4 or V6) - /// \param type option type (0-255 for V4 and 0-65535 for V6) - /// \param data content of the option - /// \param offset location of option in a packet (zero is default) + /// This constructor creates localized option using whole provided + /// option buffer. + /// + /// \param u universe (V4 or V6). + /// \param type option type (0-255 for V4 and 0-65535 for V6). + /// Option values 0 and 255 (v4) and 0 (v6) are not valid option + /// codes but they are accepted here for the server testing purposes. + /// \param data content of the option. + /// \param offset location of option in a packet (zero is default). LocalizedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data, - const size_t offset) : + const size_t offset = 0) : dhcp::Option(u, type, data), offset_(offset), option_valid_(true) { } + /// \brief Constructor, used to create option from buffer iterators. + /// + /// This constructor creates localized option using part of the + /// option buffer pointed by iterators. + /// + /// \param u specifies universe (V4 or V6) + /// \param type option type (0-255 for V4 and 0-65535 for V6) + /// \param first iterator to the first element that should be copied + /// \param last iterator to the next element after the last one + /// to be copied. + /// \param offset offset of option in a packet (zero is default) + LocalizedOption(dhcp::Option::Universe u, + uint16_t type, + dhcp::OptionBufferConstIter first, + dhcp::OptionBufferConstIter last, + const size_t offset = 0) : + dhcp::Option(u, type, first, last), + offset_(offset), option_valid_(true) { + } + /// \brief Copy constructor, creates LocalizedOption from Option6IA. /// /// This copy constructor creates regular option from Option6IA. @@ -113,44 +126,6 @@ public: } } - /// \brief Constructor, sets default (0) option offset - /// - /// This contructor is similar to the previous one, but it does not take - /// the whole vector, but rather subset of it. - /// - /// \param u specifies universe (V4 or V6) - /// \param type option type (0-255 for V4 and 0-65535 for V6) - /// \param first iterator to the first element that should be copied - /// \param last iterator to the next element after the last one - /// to be copied. - LocalizedOption(dhcp::Option::Universe u, - uint16_t type, - dhcp::OptionBufferConstIter first, - dhcp::OptionBufferConstIter last) : - dhcp::Option(u, type, first, last), - offset_(0), option_valid_(true) { - } - - - /// \brief Constructor, used to create option from buffer iterators - /// - /// This contructor is similar to the previous one, but it does not take - /// the whole vector, but rather subset of it. - /// - /// \param u specifies universe (V4 or V6) - /// \param type option type (0-255 for V4 and 0-65535 for V6) - /// \param first iterator to the first element that should be copied - /// \param last iterator to the next element after the last one - /// to be copied. - /// \param offset offset of option in a packet (zero is default) - LocalizedOption(dhcp::Option::Universe u, - uint16_t type, - dhcp::OptionBufferConstIter first, - dhcp::OptionBufferConstIter last, const size_t offset) : - dhcp::Option(u, type, first, last), - offset_(offset), option_valid_(true) { - } - /// \brief Returns offset of an option in a DHCP packet. /// /// \return option offset in a packet @@ -169,7 +144,7 @@ private: }; -} // namespace perfdhcp +} // namespace isc::perfdhcp } // namespace isc #endif // __LOCALIZED_OPTION_H diff --git a/tests/tools/perfdhcp/perf_pkt4.h b/tests/tools/perfdhcp/perf_pkt4.h index 1a19a08749..87c7bb0974 100644 --- a/tests/tools/perfdhcp/perf_pkt4.h +++ b/tests/tools/perfdhcp/perf_pkt4.h @@ -113,7 +113,6 @@ public: void writeAt(size_t dest_pos, std::vector::iterator first, std::vector::iterator last); - /// \brief Replace contents of buffer with value. /// diff --git a/tests/tools/perfdhcp/pkt_transform.cc b/tests/tools/perfdhcp/pkt_transform.cc index d87ca19c3b..b1c64e2339 100644 --- a/tests/tools/perfdhcp/pkt_transform.cc +++ b/tests/tools/perfdhcp/pkt_transform.cc @@ -221,12 +221,7 @@ void PktTransform::writeAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos, dhcp::OptionBuffer::iterator first, dhcp::OptionBuffer::iterator last) { - int i = 0; - for (std::vector::iterator it = first; - it != last; - ++it, ++i) { - in_buffer[dest_pos + i] = *it; - } + memcpy(&in_buffer[dest_pos], &(*first), std::distance(first, last)); } } // namespace perfdhcp diff --git a/tests/tools/perfdhcp/pkt_transform.h b/tests/tools/perfdhcp/pkt_transform.h index e7665a2dc8..08563a2720 100644 --- a/tests/tools/perfdhcp/pkt_transform.h +++ b/tests/tools/perfdhcp/pkt_transform.h @@ -115,7 +115,7 @@ public: static void writeValueAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos, T val) { for (int i = 0; i < sizeof(T); ++i) { - in_buffer[dest_pos + i] = (val >> (sizeof(T) - 8 * i - 1)) & 0xFF; + in_buffer[dest_pos + i] = (val >> 8 * (sizeof(T) - i - 1)) & 0xFF; } } diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index 806fb8dee6..aae6934778 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -1102,13 +1102,12 @@ public: /// Statistics includes sent, received and dropped packets /// counters. void printIntermediateStats() const { - std::ostringstream stream_sent(""); - std::ostringstream stream_rcvd(""); - std::ostringstream stream_drops(""); + std::ostringstream stream_sent; + std::ostringstream stream_rcvd; + std::ostringstream stream_drops; std::string sep(""); for (ExchangesMapIterator it = exchanges_.begin(); - it != exchanges_.end(); - ++it) { + it != exchanges_.end(); ++it) { if (it != exchanges_.begin()) { sep = "/"; diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 6da2549182..3c0f6d1b11 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -325,12 +325,12 @@ TestControl::generateMacAddress(uint8_t& randomized) const { CommandOptions& options = CommandOptions::instance(); uint32_t clients_num = options.getClientsNum(); if ((clients_num == 0) || (clients_num == 1)) { - return (options.getMacPrefix()); + return (options.getMacTemplate()); } // Get the base MAC address. We are going to randomize part of it. - std::vector mac_addr(options.getMacPrefix()); + std::vector mac_addr(options.getMacTemplate()); if (mac_addr.size() != HW_ETHER_LEN) { - isc_throw(BadValue, "invalid MAC address prefix specified"); + isc_throw(BadValue, "invalid MAC address template specified"); } uint32_t r = random(); // The random number must be in the range 0..clients_num. This @@ -364,10 +364,11 @@ TestControl::generateDuid(uint8_t& randomized) const { CommandOptions& options = CommandOptions::instance(); uint32_t clients_num = options.getClientsNum(); if ((clients_num == 0) || (clients_num == 1)) { - return (options.getDuidPrefix()); + return (options.getDuidTemplate()); } // Get the base DUID. We are going to randomize part of it. - std::vector duid(options.getDuidPrefix()); + std::vector duid(options.getDuidTemplate()); + // @todo: add support for DUIDs of different sizes. std::vector mac_addr(generateMacAddress(randomized)); duid.resize(duid.size() - mac_addr.size()); for (int i = 0; i < mac_addr.size(); ++i) { @@ -589,12 +590,11 @@ TestControl::printDiagnostics() const { // Print all command line parameters. options.printCommandLine(); // Print MAC and DUID. - std::cout << "Set MAC to " << vector2Hex(options.getMacPrefix(), "::") + std::cout << "Set MAC to " << vector2Hex(options.getMacTemplate(), "::") << std::endl; - if (options.getDuidPrefix().size() > 0) { - std::cout << "Set DUID to " << vector2Hex(options.getDuidPrefix()) << std::endl; + if (options.getDuidTemplate().size() > 0) { + std::cout << "Set DUID to " << vector2Hex(options.getDuidTemplate()) << std::endl; } - } } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 2bace3a22e..36ee55a32f 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -335,10 +335,10 @@ protected: /// simulated DHCP clients specified from command line. It uses /// \ref CommandOptions object to retrieve number of clients. /// Based on this the random value is generated and added to - /// the MAC address prefix (default MAC address). + /// the MAC address template (default MAC address). /// /// \param randomized number of bytes randomized. - /// \throw isc::BadValue if MAC address prefix (default or specified + /// \throw isc::BadValue if MAC address template (default or specified /// from the command line) has invalid size (expected 6 octets). /// \return generated MAC address. std::vector generateMacAddress(uint8_t& randomized) const; diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index faed8a1e6f..01f0357a70 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ using namespace std; using namespace isc; using namespace isc::perfdhcp; +using namespace boost::posix_time; /// \brief Test Fixture Class /// @@ -72,7 +74,7 @@ protected: // default mac const uint8_t mac[6] = { 0x00, 0x0C, 0x01, 0x02, 0x03, 0x04 }; - std::vector v1 = opt.getMacPrefix(); + std::vector v1 = opt.getMacTemplate(); ASSERT_EQ(6, v1.size()); EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); @@ -85,10 +87,27 @@ protected: // of time value and 6 octets of variable link layer (MAC) // address. const int duid_llt_size = 14; - std::vector v2 = opt.getDuidPrefix(); - ASSERT_EQ(duid_llt_size, opt.getDuidPrefix().size()); + std::vector v2 = opt.getDuidTemplate(); + ASSERT_EQ(duid_llt_size, opt.getDuidTemplate().size()); EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4, duid_llt_and_hw)); + // Check time field contents. + ptime now = microsec_clock::universal_time(); + ptime duid_epoch(from_iso_string("20000101T000000")); + time_period period(duid_epoch, now); + uint32_t duration_sec = period.length().total_seconds(); + // Read time from the template generated. + uint32_t duration_from_template = 0; + memcpy(&duration_from_template, &v2[4], 4); + duration_from_template = htonl(duration_from_template); + // In special cases, we may have overflow in time field + // so we give ourselves the margin of 10 seconds here. + // If time value has been set more then 10 seconds back + // it is safe to compare it with the time value generated + // from now. + if (duration_from_template > 10) { + EXPECT_GE(duration_sec, duration_from_template); + } EXPECT_EQ(0, opt.getBase().size()); EXPECT_EQ(0, opt.getNumRequests().size()); @@ -249,7 +268,7 @@ TEST_F(CommandOptionsTest, Base) { 0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 }; // Test Mac - std::vector v1 = opt.getMacPrefix(); + std::vector v1 = opt.getMacTemplate(); ASSERT_EQ(6, v1.size()); EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); // "3x" is invalid value in MAC address @@ -260,7 +279,7 @@ TEST_F(CommandOptionsTest, Base) { EXPECT_NO_THROW( process("perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all") ); - std::vector v2 = opt.getDuidPrefix(); + std::vector v2 = opt.getDuidTemplate(); ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size()); EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); // "t" is invalid character in DUID diff --git a/tests/tools/perfdhcp/tests/perf_pkt4_unittest.cc b/tests/tools/perfdhcp/tests/perf_pkt4_unittest.cc index 3863faa111..5523c640ec 100644 --- a/tests/tools/perfdhcp/tests/perf_pkt4_unittest.cc +++ b/tests/tools/perfdhcp/tests/perf_pkt4_unittest.cc @@ -381,4 +381,50 @@ TEST_F(PerfPkt4Test, UnpackTransactionId) { EXPECT_FALSE(pkt2->rawUnpack()); } +TEST_F(PerfPkt4Test, Writes) { + // Initialize intput buffer with 260 elements set to value 1. + dhcp::OptionBuffer in_data(260, 1); + // Initialize buffer to be used for write: 1,2,3,4,...,9 + dhcp::OptionBuffer write_buf(10); + for (int i = 0; i < write_buf.size(); ++i) { + write_buf[i] = i; + } + // Create packet from the input buffer. + const size_t transid_offset = 4; + boost::scoped_ptr pkt1(new PerfPkt4(&in_data[0], + in_data.size(), + transid_offset)); + // Write numbers 4,5,6,7 to the packet's input buffer at position 10. + pkt1->writeAt(10, write_buf.begin() + 3, write_buf.begin() + 7); + // We have to pack data to output buffer here because Pkt4 provides no + // way to retrieve input buffer. If we pack data it will go to + // output buffer that has getter available. + ASSERT_TRUE(pkt1->rawPack()); + const util::OutputBuffer& out_buf = pkt1->getBuffer(); + ASSERT_EQ(in_data.size(), out_buf.getLength()); + // Verify that 4,5,6,7 has been written to the packet's buffer. + const char* out_data = static_cast(out_buf.getData()); + EXPECT_TRUE(std::equal(write_buf.begin() + 3, write_buf.begin() + 7, + out_data + 10)); + // Write 1 octet (0x51) at position 10. + pkt1->writeValueAt(10, 0x51); + ASSERT_TRUE(pkt1->rawPack()); + ASSERT_EQ(in_data.size(), pkt1->getBuffer().getLength()); + EXPECT_EQ(0x51, pkt1->getBuffer()[10]); + // Write 2 octets (0x5251) at position 20. + pkt1->writeValueAt(20, 0x5251); + ASSERT_TRUE(pkt1->rawPack()); + ASSERT_EQ(in_data.size(), pkt1->getBuffer().getLength()); + EXPECT_EQ(0x52, pkt1->getBuffer()[20]); + EXPECT_EQ(0x51, pkt1->getBuffer()[21]); + // Write 4 octets (0x54535251) at position 30. + pkt1->writeValueAt(30, 0x54535251); + ASSERT_TRUE(pkt1->rawPack()); + ASSERT_EQ(in_data.size(), pkt1->getBuffer().getLength()); + EXPECT_EQ(0x54, pkt1->getBuffer()[30]); + EXPECT_EQ(0x53, pkt1->getBuffer()[31]); + EXPECT_EQ(0x52, pkt1->getBuffer()[32]); + EXPECT_EQ(0x51, pkt1->getBuffer()[33]); +} + } diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index d72cd0f755..2ea3667ab6 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -215,7 +215,7 @@ public: // The old duid will be holding the previously generated DUID. // It will be used to compare against the new one. If we have // multiple clients we want to make sure that duids differ. - Duid old_duid(CommandOptions::instance().getDuidPrefix()); + Duid old_duid(CommandOptions::instance().getDuidTemplate()); Duid new_duid(0); // total_dist shows the total difference between generated duid. // It has to be greater than zero if multiple clients are simulated. @@ -439,7 +439,7 @@ public: // MAC address. We will be comparing the newly generated one with it // to see if it changes when mulitple clients are simulated or if it // does not change when single client is simulated. - MacAddress old_mac(CommandOptions::instance().getMacPrefix()); + MacAddress old_mac(CommandOptions::instance().getMacTemplate()); // Holds the position if the octet on which two MAC addresses can // be different. If number of clients is 256 or less it is last MAC // octet (except for single client when subsequent MAC addresses @@ -652,7 +652,7 @@ TEST_F(TestControlTest, Options6) { EXPECT_THROW(opt_rapid_commit->getUint8(), isc::OutOfRange); // Validate the D6O_CLIENTID option. - OptionBuffer duid(CommandOptions::instance().getDuidPrefix()); + OptionBuffer duid(CommandOptions::instance().getDuidTemplate()); OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid)); EXPECT_EQ(Option::V6, opt_clientid->getUniverse()); EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType()); From ad297b10887895eae9cb6e3c5e00e38f7d1f5fda Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 4 Sep 2012 11:12:14 +0200 Subject: [PATCH 095/148] [1959] A couple of minor changes to cover second part of the review. --- tests/tools/perfdhcp/stats_mgr.h | 22 ++++++++++++++----- tests/tools/perfdhcp/test_control.h | 8 +++++-- .../tests/command_options_unittest.cc | 10 +++++++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/tests/tools/perfdhcp/stats_mgr.h b/tests/tools/perfdhcp/stats_mgr.h index aae6934778..a8dfa8b7bd 100644 --- a/tests/tools/perfdhcp/stats_mgr.h +++ b/tests/tools/perfdhcp/stats_mgr.h @@ -214,15 +214,27 @@ public: /// } /// \endcode typedef boost::multi_index_container< + // Container holds shared_ptr or shared_ptr objects. boost::shared_ptr, + // List container indexes. boost::multi_index::indexed_by< + // Sequenced index provides the way to use this container + // in the same way as std::list. boost::multi_index::sequenced<>, + // The other index keeps products of transaction id. boost::multi_index::hashed_non_unique< - boost::multi_index::global_fun< - const boost::shared_ptr&, - uint32_t, - &ExchangeStats::hashTransid - > + // Specify hash function to get the product of + // transaction id. This product is obtained by calling + // hashTransid() function. + boost::multi_index::global_fun< + // Hashing function takes shared_ptr or + // shared_ptr as argument. + const boost::shared_ptr&, + // ... and returns uint32 value. + uint32_t, + // ... and here is a reference to it. + &ExchangeStats::hashTransid + > > > > PktList; diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 36ee55a32f..5994006cea 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -108,7 +108,7 @@ public: /// \brief Destriuctor of the socket wrapper class. /// /// Destructor closes all open sockets on all interfaces. - /// TODO: close only the socket being wrapped by this class. + /// \todo close only the socket being wrapped by this class. ~TestControlSocket(); /// \brief Return name of the interface where socket is bound to. @@ -254,7 +254,9 @@ protected: /// \brief Factory function to create IA_NA option. /// /// This factory function creates DHCPv6 IA_NA option instance. - /// \TODO: add support for IA Address options. + /// + /// \todo add support for IA Address options. + /// /// \param u universe (V6 or V4). /// \param type option-type. /// \param buf option-buffer. @@ -323,6 +325,8 @@ protected: /// from the MAC address, this function uses \ref generateMacAddress /// internally to randomize the DUID. /// + /// \todo add support for other types of DUID. + /// /// \param randomized number of bytes randomized. /// \throw isc::BadValue if \ref generateMacAddress throws. /// \return vector representing DUID. diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index 01f0357a70..70cb77d787 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -86,7 +86,10 @@ protected: // DUID_LLT value, two octets of hardware type, 4 octets // of time value and 6 octets of variable link layer (MAC) // address. - const int duid_llt_size = 14; + const int duid_llt_size = 14; + // DUID is not given from the command line but it is supposed + // to be initialized by the CommandOptions private method + // generateDuidTemplate(). std::vector v2 = opt.getDuidTemplate(); ASSERT_EQ(duid_llt_size, opt.getDuidTemplate().size()); EXPECT_TRUE(std::equal(v2.begin(), v2.begin() + 4, @@ -548,6 +551,9 @@ TEST_F(CommandOptionsTest, Interface) { // In order to make this test portable we need to know // at least one interface name on OS where test is run. // Interface Manager has ability to detect interfaces. + // Altough we don't call initIsInterface explicitely + // here it is called by CommandOptions object interally + // so this function is covered by the test. dhcp::IfaceMgr& iface_mgr = dhcp::IfaceMgr::instance(); const dhcp::IfaceMgr::IfaceCollection& ifaces = iface_mgr.getIfaces(); std::string iface_name; @@ -568,7 +574,7 @@ TEST_F(CommandOptionsTest, Interface) { // exception is expected to be thrown. EXPECT_THROW(process("perfdhcp -4"), isc::InvalidParameter); } -} +} TEST_F(CommandOptionsTest, Server) { CommandOptions& opt = CommandOptions::instance(); From c2fa97e23503ea00f82e0adff38d14473f475da8 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 4 Sep 2012 16:39:23 +0200 Subject: [PATCH 096/148] [1959] Implemented changes from the 3rd part of code review. --- tests/tools/perfdhcp/test_control.cc | 118 +++++++---- tests/tools/perfdhcp/test_control.h | 190 +++++++++--------- .../perfdhcp/tests/test_control_unittest.cc | 18 +- 3 files changed, 182 insertions(+), 144 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 3c0f6d1b11..6e7fa05654 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -45,14 +45,21 @@ namespace perfdhcp { bool TestControl::interrupted_ = false; -TestControl::TestControlSocket::TestControlSocket(int socket) : - socket_(socket), - addr_("127.0.0.1") { - initSocketData(); +TestControl::TestControlSocket::TestControlSocket(const int socket) : + SocketInfo(socket, asiolink::IOAddress("127.0.0.1"), 0), + ifindex_(0), valid_(true) { + try { + initSocketData(); + } catch (const Exception&) { + valid_ = false; + } } TestControl::TestControlSocket::~TestControlSocket() { - IfaceMgr::instance().closeSockets(); + IfaceMgr::Iface* iface = IfaceMgr::instance().getIface(ifindex_); + if (iface) { + iface->delSocket(sockfd_); + } } void @@ -68,8 +75,7 @@ TestControl::TestControlSocket::initSocketData() { socket_collection.begin(); s != socket_collection.end(); ++s) { - if (s->sockfd_ == socket_) { - iface_ = it->getName(); + if (s->sockfd_ == sockfd_) { ifindex_ = it->getIndex(); addr_ = s->addr_; return; @@ -269,6 +275,7 @@ TestControl::factoryGeneric(Option::Universe u, uint16_t type, OptionPtr TestControl::factoryIana6(Option::Universe, uint16_t, const OptionBuffer& buf) { + // @todo allow different values of T1, T2 and IAID. const uint8_t buf_array[] = { 0, 0, 0, 1, // IAID = 1 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600 @@ -333,7 +340,7 @@ TestControl::generateMacAddress(uint8_t& randomized) const { isc_throw(BadValue, "invalid MAC address template specified"); } uint32_t r = random(); - // The random number must be in the range 0..clients_num. This + // The random number must be in the range 0..clients_num-1. This // will guarantee that every client has exactly one random MAC // address assigned. r %= clients_num; @@ -370,13 +377,31 @@ TestControl::generateDuid(uint8_t& randomized) const { std::vector duid(options.getDuidTemplate()); // @todo: add support for DUIDs of different sizes. std::vector mac_addr(generateMacAddress(randomized)); - duid.resize(duid.size() - mac_addr.size()); - for (int i = 0; i < mac_addr.size(); ++i) { - duid.push_back(mac_addr[i]); - } + duid.resize(duid.size()); + std::copy(mac_addr.begin(), mac_addr.end(), + duid.begin() + duid.size() - mac_addr.size()); return (duid); } +template +uint32_t +TestControl::getElapsedTime(const T& pkt1, const T& pkt2) { + using namespace boost::posix_time; + ptime pkt1_time = pkt1->getTimestamp(); + ptime pkt2_time = pkt2->getTimestamp(); + if (pkt1_time.is_not_a_date_time() || + pkt2_time.is_not_a_date_time()) { + isc_throw(InvalidOperation, "packet timestamp not set");; + } + time_period elapsed_period(pkt1_time, pkt2_time); + if (elapsed_period.is_null()) { + isc_throw(InvalidOperation, "unable to calculate time elapsed" + " between packets"); + } + return(elapsed_period.length().total_milliseconds()); +} + + uint64_t TestControl::getNextExchangesNum() const { CommandOptions& options = CommandOptions::instance(); @@ -399,7 +424,9 @@ TestControl::getNextExchangesNum() const { // of exchanges to be initiated. due_exchanges = static_cast(due_factor * options.getRate()); // We want to make sure that at least one packet goes out. - due_exchanges += 1; + if (due_exchanges == 0) { + due_exchanges = 1; + } // We should not exceed aggressivity as it could have been // restricted from command line. if (due_exchanges > options.getAggressivity()) { @@ -441,7 +468,7 @@ TestControl::getTemplateBuffer(const size_t idx) const { if (template_buffers_.size() > idx) { return (template_buffers_[idx]); } - return (TemplateBuffer()); + isc_throw(OutOfRange, "invalid buffer index"); } void @@ -455,8 +482,7 @@ TestControl::initPacketTemplates() { CommandOptions& options = CommandOptions::instance(); std::vector template_files = options.getTemplateFiles(); for (std::vector::const_iterator it = template_files.begin(); - it != template_files.end(); - ++it) { + it != template_files.end(); ++it) { readPacketTemplate(*it); } } @@ -738,10 +764,13 @@ TestControl::receivePacket6(const TestControlSocket& socket, CommandOptions::ExchangeMode xchg_mode = CommandOptions::instance().getExchangeMode(); if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) { + // \todo check whether received ADVERTISE packet is sane. + // We might want to check if STATUS_CODE option is non-zero + // and if there is IAADR option in IA_NA. if (template_buffers_.size() < 2) { - sendRequest6(socket, solicit_pkt6, pkt6); + sendRequest6(socket, pkt6); } else { - sendRequest6(socket, template_buffers_[1], solicit_pkt6, pkt6); + sendRequest6(socket, template_buffers_[1], pkt6); } } } else if (packet_type == DHCPV6_REPLY) { @@ -880,16 +909,25 @@ TestControl::run() { "command options must be parsed before running a test"); } - // Diagnostics is command line options mainly. + // Diagnostics are command line options mainly. printDiagnostics(); // Option factories have to be registered. registerOptionFactories(); TestControlSocket socket(openSocket()); + if (!socket.valid_) { + isc_throw(Unexpected, "invalid socket descriptor"); + } // Initialize packet templates. initPacketTemplates(); // Initialize randomization seed. if (options.isSeeded()) { srandom(options.getSeed()); + } else { + // Seed with current time. + time_period duration(from_iso_string("20111231T235959"), + microsec_clock::universal_time()); + srandom(duration.length().total_seconds() + + duration.length().fractional_seconds()); } // If user interrupts the program we will exit gracefully. signal(SIGINT, TestControl::handleInterrupt); @@ -898,10 +936,12 @@ TestControl::run() { for (int i = 0; i < options.getPreload(); ++i) { if (options.getIpVersion() == 4) { // No template buffer means no -T option specified. - // We will build packet ourselfs. + // We will build packet ourselves. if (template_buffers_.size() == 0) { sendDiscover4(socket, do_preload); } else { + // Pick template #0 if Discover is being sent. + // For Request it would be #1. const uint8_t template_idx = 0; sendDiscover4(socket, template_buffers_[template_idx], do_preload); @@ -912,6 +952,8 @@ TestControl::run() { if (template_buffers_.size() == 0) { sendSolicit6(socket, do_preload); } else { + // Pick template #0 if Solicit is being sent. + // For Request it would be #1. const uint8_t template_idx = 0; sendSolicit6(socket, template_buffers_[template_idx], do_preload); @@ -1187,7 +1229,7 @@ TestControl::sendRequest4(const TestControlSocket& socket, std::vector mac_address(chaddr, chaddr + HW_ETHER_LEN); pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end()); - // Set elapsed time. + // Set elapsed time. size_t elp_offset = 0; if (options.getElapsedTimeOffset() > 0) { elp_offset = options.getElapsedTimeOffset(); @@ -1266,16 +1308,12 @@ TestControl::sendRequest4(const TestControlSocket& socket, void TestControl::sendRequest6(const TestControlSocket& socket, - const Pkt6Ptr& solicit_pkt6, const Pkt6Ptr& advertise_pkt6) { const uint32_t transid = generateTransid(); Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid)); // Set elapsed time. - const uint32_t elapsed_time = - getElapsedTime(solicit_pkt6, advertise_pkt6); OptionPtr opt_elapsed_time = Option::factory(Option::V6, D6O_ELAPSED_TIME); - opt_elapsed_time->setUint16(static_cast(elapsed_time / 10)); pkt6->addOption(opt_elapsed_time); // Set client id. OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID); @@ -1323,7 +1361,6 @@ TestControl::sendRequest6(const TestControlSocket& socket, void TestControl::sendRequest6(const TestControlSocket& socket, const std::vector& template_buf, - const Pkt6Ptr& solicit_pkt6, const Pkt6Ptr& advertise_pkt6) { CommandOptions& options = CommandOptions::instance(); // Get the second argument if multiple the same arguments specified @@ -1343,12 +1380,9 @@ TestControl::sendRequest6(const TestControlSocket& socket, if (options.getElapsedTimeOffset() > 0) { elp_offset = options.getElapsedTimeOffset(); } - uint32_t elapsed_time = - getElapsedTime(solicit_pkt6, advertise_pkt6); boost::shared_ptr opt_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(), elp_offset)); - opt_elapsed_time->setUint16(static_cast(elapsed_time / 10)); pkt6->addOption(opt_elapsed_time); // Get the actual server id offset. @@ -1537,9 +1571,13 @@ TestControl::setDefaults4(const TestControlSocket& socket, const Pkt4Ptr& pkt) { CommandOptions& options = CommandOptions::instance(); // Interface name. - pkt->setIface(socket.getIface()); + IfaceMgr::Iface* iface = IfaceMgr::instance().getIface(socket.ifindex_); + if (iface == NULL) { + isc_throw(BadValue, "unable to find interface with given index"); + } + pkt->setIface(iface->getName()); // Interface index. - pkt->setIndex(socket.getIfIndex()); + pkt->setIndex(socket.ifindex_); // Local client's port (68) pkt->setLocalPort(DHCP4_CLIENT_PORT); // Server's port (67) @@ -1547,9 +1585,9 @@ TestControl::setDefaults4(const TestControlSocket& socket, // The remote server's name or IP. pkt->setRemoteAddr(IOAddress(options.getServerName())); // Set local addresss. - pkt->setLocalAddr(IOAddress(socket.getAddress())); + pkt->setLocalAddr(IOAddress(socket.addr_)); // Set relay (GIADDR) address to local address. - pkt->setGiaddr(IOAddress(socket.getAddress())); + pkt->setGiaddr(IOAddress(socket.addr_)); // Pretend that we have one relay (which is us). pkt->setHops(1); } @@ -1559,15 +1597,19 @@ TestControl::setDefaults6(const TestControlSocket& socket, const Pkt6Ptr& pkt) { CommandOptions& options = CommandOptions::instance(); // Interface name. - pkt->setIface(socket.getIface()); + IfaceMgr::Iface* iface = IfaceMgr::instance().getIface(socket.ifindex_); + if (iface == NULL) { + isc_throw(BadValue, "unable to find interface with given index"); + } + pkt->setIface(iface->getName()); // Interface index. - pkt->setIndex(socket.getIfIndex()); + pkt->setIndex(socket.ifindex_); // Local client's port (547) pkt->setLocalPort(DHCP6_CLIENT_PORT); // Server's port (548) pkt->setRemotePort(DHCP6_SERVER_PORT); // Set local address. - pkt->setLocalAddr(socket.getAddress()); + pkt->setLocalAddr(socket.addr_); // The remote server's name or IP. pkt->setRemoteAddr(IOAddress(options.getServerName())); } @@ -1606,6 +1648,10 @@ TestControl::updateSendDue() { send_due_ = last_sent_ + time_duration(0, 0, 0, duration); // Check if it is already due. ptime now(microsec_clock::universal_time()); + // \todo verify if this condition is not too tight. In other words + // verify if this will not produce too many late sends. + // We might want to look at this once we are done implementing + // microsecond timeouts in IfaceMgr. if (now > send_due_) { if (testDiags('i')) { if (options.getIpVersion() == 4) { diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 5994006cea..cf83113daf 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ namespace perfdhcp { class TestControl : public boost::noncopyable { public: - /// Default transaction id offset. + /// Default transaction id offset. static const size_t DHCPV4_TRANSID_OFFSET = 4; /// Default offset of MAC's last octet. static const size_t DHCPV4_RANDOMIZATION_OFFSET = 35; @@ -84,55 +85,38 @@ public: /// Packet template buffers list. typedef std::vector TemplateBufferCollection; - /// \brief Socket wrapper class. + /// \brief Socket wrapper structure. /// - /// This is wrapper class that holds descriptor of the socket - /// used to run DHCP test. All sockets created with \ref IfaceMgr - /// are closed in the destructor. This ensures that socket is - /// closed when the function that created the socket ends - /// (normally or when exception occurs). - class TestControlSocket { - public: + /// This is the wrapper that holds descriptor of the socket + /// used to run DHCP test. The wrapped socket is closed in + /// the destructor. This prevents resource leaks when when + /// function that created the socket ends (normally or + /// when exception occurs). This structure extends parent + /// structure with new field ifindex_ that holds interface + /// index where socket is bound to. + struct TestControlSocket : public dhcp::IfaceMgr::SocketInfo { + /// Interface index. + uint16_t ifindex_; + /// Is socket valid. It will not be valid if the provided socket + /// descriptor does not point to valid socket. + bool valid_; /// \brief Constructor of socket wrapper class. /// /// This constructor uses provided socket descriptor to /// find the name of the interface where socket has been - /// bound to. + /// bound to. If provided socket descriptor is invalid then + /// valid_ field is set to false; /// /// \param socket socket descriptor. - /// \throw isc::BadValue if interface for specified - /// socket descriptor does not exist. TestControlSocket(const int socket); /// \brief Destriuctor of the socket wrapper class. /// - /// Destructor closes all open sockets on all interfaces. - /// \todo close only the socket being wrapped by this class. + /// Destructor closes wrapped socket. ~TestControlSocket(); - /// \brief Return name of the interface where socket is bound to. - /// - /// \return name of the interface where socket is bound to. - const std::string& getIface() const { return(iface_); } - - /// \brief Return interface index where socket is bound to. - /// - /// \return index fo the interface where sockert is bound to. - int getIfIndex() const { return(ifindex_); } - - /// \brief Return address where socket is bound to. - /// - /// \return address where socket is bound to. - const asiolink::IOAddress& getAddress() const { return(addr_); } - private: - /// \brief Private default constructor. - /// - /// Default constructor is private to make sure that valid - /// socket descriptor is passed to create object. - TestControlSocket(); - /// \brief Initialize socket data. /// /// This method initializes members of the class that Interface @@ -141,11 +125,6 @@ public: /// \throw isc::BadValue if interface for specified socket /// descriptor does not exist. void initSocketData(); - - int socket_; ///< Socket descirptor. - std::string iface_; ///< Name of the interface. - int ifindex_; ///< Index of the interface. - asiolink::IOAddress addr_; ///< Address bound. }; /// \brief Default transaction id generator class. @@ -169,6 +148,9 @@ public: typedef boost::shared_ptr TransidGeneratorPtr; /// \brief Length of the Ethernet HW address (MAC) in bytes. + /// + /// \todo Make this variable length as there are cases when HW + /// address is longer than this (e.g. 20 bytes). static const uint8_t HW_ETHER_LEN = 6; /// TestControl is a singleton class. This method returns reference @@ -195,22 +177,20 @@ public: transid_gen_ = generator; } -protected: - - // We would really like these methods and members to be private but + // We would really like following methods and members to be private but // they have to be accessible for unit-testing. Another, possibly better, // solution is to make this class friend of test class but this is not // what's followed in other classes. - +protected: /// \brief Default constructor. /// /// Default constructor is protected as the object can be created /// only via \ref instance method. TestControl(); - /// \brief Check if test exit condtitions fulfiled. + /// \brief Check if test exit condtitions fulfilled. /// - /// Method checks if test exit conditions are fulfiled. + /// Method checks if the test exit conditions are fulfiled. /// Exit conditions are checked periodically from the /// main loop. Program should break the main loop when /// this method returns true. It is calling function @@ -227,9 +207,10 @@ protected: /// to length 2 and values will be initialized to zeros. Otherwise /// function will initialize option buffer with values in passed buffer. /// - /// \param u universe (V6 or V4). - /// \param type option-type. - /// \param buf option-buffer. + /// \param u universe (ignored) + /// \param type option-type (ignored). + /// \param buf option-buffer containing option content (2 bytes) or + /// empty buffer if option content has to be set to default (0) value. /// \throw if elapsed time buffer size is neither 2 nor 0. /// \return instance o the option. static dhcp::OptionPtr @@ -244,7 +225,7 @@ protected: /// the buffer contents, size etc. /// /// \param u universe (V6 or V4). - /// \param type option-type. + /// \param type option-type (ignored). /// \param buf option-buffer. /// \return instance o the option. static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u, @@ -257,9 +238,9 @@ protected: /// /// \todo add support for IA Address options. /// - /// \param u universe (V6 or V4). - /// \param type option-type. - /// \param buf option-buffer. + /// \param u universe (ignored). + /// \param type option-type (ignored). + /// \param buf option-buffer carrying IANA suboptions. /// \return instance of IA_NA option. static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u, uint16_t type, @@ -272,9 +253,9 @@ protected: /// - D6O_NAME_SERVERS /// - D6O_DOMAIN_SEARCH /// - /// \param u universe (V6 or V4). - /// \param type option-type. - /// \param buf option-buffer (ignored and should be empty). + /// \param u universe (ignored). + /// \param type option-type (ignored). + /// \param buf option-buffer (ignored). /// \return instance of ORO option. static dhcp::OptionPtr factoryOptionRequestOption6(dhcp::Option::Universe u, @@ -287,9 +268,9 @@ protected: /// The buffer passed to this option must be empty because option does /// not have any payload. /// - /// \param u universe (V6 or V4). - /// \param type option-type. - /// \param buf option-buffer (ignored and should be empty). + /// \param u universe (ignored). + /// \param type option-type (ignored). + /// \param buf option-buffer (ignored). /// \return instance of RAPID_COMMIT option.. static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u, uint16_t type, @@ -308,9 +289,9 @@ protected: /// - DHO_DOMAIN_NAME_SERVERS, /// - DHO_HOST_NAME. /// - /// \param u universe (V6 or V4). - /// \param type option-type. - /// \param buf option-buffer (ignored and should be empty). + /// \param u universe (ignored). + /// \param type option-type (ignored). + /// \param buf option-buffer (ignored). /// \return instance o the generic option. static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, @@ -319,15 +300,16 @@ protected: /// \brief Generate DUID. /// /// Method generates unique DUID. The number of DUIDs it can generate - /// depends on the number of simulated clinets, which is specified + /// depends on the number of simulated clients, which is specified /// from the command line. It uses \ref CommandOptions object to retrieve - /// number of clinets. Since the last six octets of DUID are constructed + /// number of clients. Since the last six octets of DUID are constructed /// from the MAC address, this function uses \ref generateMacAddress /// internally to randomize the DUID. /// /// \todo add support for other types of DUID. /// - /// \param randomized number of bytes randomized. + /// \param [out] randomized number of bytes randomized (initial value + /// is ignored). /// \throw isc::BadValue if \ref generateMacAddress throws. /// \return vector representing DUID. std::vector generateDuid(uint8_t& randomized) const; @@ -341,7 +323,8 @@ protected: /// Based on this the random value is generated and added to /// the MAC address template (default MAC address). /// - /// \param randomized number of bytes randomized. + /// \param [out] randomized number of bytes randomized (initial + /// value is ignored). /// \throw isc::BadValue if MAC address template (default or specified /// from the command line) has invalid size (expected 6 octets). /// \return generated MAC address. @@ -349,6 +332,9 @@ protected: /// \brief generate transaction id. /// + /// Generate transaction id value (32-bit for DHCPv4, + /// 24-bit for DHCPv6). + /// /// \return generated transaction id. uint32_t generateTransid() { return(transid_gen_->generate()); @@ -361,7 +347,7 @@ protected: /// is based on current time, due time calculated with /// \ref updateSendTime function and expected rate. /// - /// \return number of exchanges to be started immediatelly. + /// \return number of exchanges to be started immediately. uint64_t getNextExchangesNum() const; /// \brief Return template buffer. @@ -369,14 +355,15 @@ protected: /// Method returns template buffer at specified index. /// /// \param idx index of template buffer. - /// \return reference to template buffer or empty buffer if index - /// is out of bounds. + /// \throw isc::OutOfRange if buffer index out of bounds. + /// \return reference to template buffer. TemplateBuffer getTemplateBuffer(const size_t idx) const; /// \brief Reads packet templates from files. /// /// Method iterates through all specified template files, reads - /// their content and stores it in class internal buffers + /// their content and stores it in class internal buffers. Template + /// file names are specified from the command line with -T option. /// /// \throw isc::BadValue if any of the template files does not exist void initPacketTemplates(); @@ -390,13 +377,13 @@ protected: /// \brief Open socket to communicate with DHCP server. /// /// Method opens socket and binds it to local address. Function will - /// can use either interface name, local address or server address + /// use either interface name, local address or server address /// to create a socket, depending on what is available (specified /// from the command line). If socket can't be created for any /// reason, exception is thrown. /// If destination address is broadcast (for DHCPv4) or multicast /// (for DHCPv6) than broadcast or multicast option is set on - /// the socket. + /// the socket. Opened socket is registered and managed by IfaceMgr. /// /// \throw isc::BadValue if socket can't be created for given /// interface, local address or remote address. @@ -432,8 +419,11 @@ protected: /// when OFFER packet arrives, this function will initiate /// REQUEST message to the server. /// - /// \param socket socket to be used. - /// \param pkt4 object representing DHCPv4 packet received. + /// \warning this method does not check if provided socket is + /// valid (specifically if v4 socket for received v4 packet). + /// + /// \param [in] socket socket to be used. + /// \param [in] pkt4 object representing DHCPv4 packet received. /// \throw isc::BadValue if unknown message type received. /// \throw isc::Unexpected if unexpected error occured. void receivePacket4(const TestControlSocket& socket, @@ -446,8 +436,11 @@ protected: /// when ADVERTISE packet arrives, this function will initiate /// REQUEST message to the server. /// - /// \param socket socket to be used. - /// \param pkt6 object representing DHCPv6 packet received. + /// \warning this method does not check if provided socket is + /// valid (specifically if v4 socket for received v4 packet). + /// + /// \param [in] socket socket to be used. + /// \param [in] pkt6 object representing DHCPv6 packet received. /// \throw isc::BadValue if unknown message type received. /// \throw isc::Unexpected if unexpected error occured. void receivePacket6(const TestControlSocket& socket, @@ -460,6 +453,9 @@ protected: /// \ref receivePacket6 depending if DHCPv4 or DHCPv6 packet /// has arrived. /// + /// \warning this method does not check if provided socket is + /// valid. Ensure that it is valid prior to calling it. + /// /// \param socket socket to be used. /// \throw::BadValue if unknown message type received. /// \throw::Unexpected if unexpected error occured. @@ -506,6 +502,8 @@ protected: /// The transaction id and MAC address are randomly generated for /// the message. Range of unique MAC addresses generated depends /// on the number of clients specified from the command line. + /// Copy of sent packet is stored in the stats_mgr4_ object to + /// update statistics. /// /// \param socket socket to be used to send the message. /// \param preload preload mode, packets not included in statistics. @@ -520,6 +518,8 @@ protected: /// template data is exepcted to be in binary format. Provided /// buffer is copied and parts of it are replaced with actual /// data (e.g. MAC address, transaction id etc.). + /// Copy of sent packet is stored in the stats_mgr4_ object to + /// update statistics. /// /// \param socket socket to be used to send the message. /// \param template_buf buffer holding template packet. @@ -532,6 +532,8 @@ protected: /// \brief Send DHCPv4 REQUEST message. /// /// Method creates and sends DHCPv4 REQUEST message to the server. + /// Copy of sent packet is stored in the stats_mgr4_ object to + /// update statistics. /// /// \param socket socket to be used to send message. /// \param discover_pkt4 DISCOVER packet sent. @@ -546,6 +548,8 @@ protected: /// \brief Send DHCPv4 REQUEST message from template. /// /// Method sends DHCPv4 REQUEST message from template. + /// Copy of sent packet is stored in the stats_mgr4_ object to + /// update statistics. /// /// \param socket socket to be used to send message. /// \param template_buf buffer holding template packet. @@ -563,32 +567,28 @@ protected: /// - D6O_ELAPSED_TIME /// - D6O_CLIENTID /// - D6O_SERVERID - /// The elapsed time is calculated based on the duration between - /// sending a SOLICIT and receiving the ADVERTISE packet prior. - /// For this reason both solicit and advertise packet objects have - /// to be passed when calling this function. + /// Copy of sent packet is stored in the stats_mgr6_ object to + /// update statistics. /// /// \param socket socket to be used to send message. - /// \param solicit_pkt6 SOLICIT packet object. /// \param advertise_pkt6 ADVERTISE packet object. /// \throw isc::Unexpected if unexpected error occured. /// \throw isc::InvalidOperation if Statistics Manager has not been /// initialized. void sendRequest6(const TestControlSocket& socket, - const dhcp::Pkt6Ptr& solicit_pkt6, const dhcp::Pkt6Ptr& advertise_pkt6); /// \brief Send DHCPv6 REQUEST message from template. /// /// Method sends DHCPv6 REQUEST message from template. + /// Copy of sent packet is stored in the stats_mgr6_ object to + /// update statistics. /// /// \param socket socket to be used to send message. /// \param template_buf packet template buffer. - /// \param solicit_pkt6 SOLICIT packet object. /// \param advertise_pkt6 ADVERTISE packet object. void sendRequest6(const TestControlSocket& socket, const std::vector& template_buf, - const dhcp::Pkt6Ptr& solicit_pkt6, const dhcp::Pkt6Ptr& advertise_pkt6); /// \brief Send DHCPv6 SOLICIT message. @@ -600,6 +600,8 @@ protected: /// - D6O_CLIENTID, /// - D6O_ORO (Option Request Option), /// - D6O_IA_NA. + /// Copy of sent packet is stored in the stats_mgr6_ object to + /// update statistics. /// /// \param socket socket to be used to send the message. /// \param preload mode, packets not included in statistics. @@ -610,6 +612,8 @@ protected: /// \brief Send DHCPv6 SOLICIT message from template. /// /// Method sends DHCPv6 SOLICIT message from template. + /// Copy of sent packet is stored in the stats_mgr6_ object to + /// update statistics. /// /// \param socket socket to be used to send the message. /// \param template_buf packet template buffer. @@ -648,7 +652,7 @@ protected: void setDefaults6(const TestControlSocket& socket, const dhcp::Pkt6Ptr& pkt); - /// \brief Find of diagnostic flag has been set. + /// \brief Find if diagnostic flag has been set. /// /// \param diag diagnostic flag (a,e,i,s,r,t,T). /// \return true if diagnostics flag has been set. @@ -674,22 +678,10 @@ private: /// \param T Pkt4Ptr or Pkt6Ptr class. /// \param pkt1 first packet. /// \param pkt2 second packet. + /// \throw InvalidOperation if packet timestamps are invalid. /// \return elapsed time in milliseconds between pkt1 and pkt2. template - uint32_t getElapsedTime(const T& pkt1, const T& pkt2) { - using namespace boost::posix_time; - ptime pkt1_time = pkt1->getTimestamp(); - ptime pkt2_time = pkt2->getTimestamp(); - if (pkt1_time.is_not_a_date_time() || - pkt2_time.is_not_a_date_time()) { - return (0); - } - time_period elapsed_period(pkt1_time, pkt2_time); - if (elapsed_period.is_null()) { - return (0); - } - return(elapsed_period.length().total_milliseconds()); - } + uint32_t getElapsedTime(const T& pkt1, const T& pkt2); /// \brief Get number of received packets. /// diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 2ea3667ab6..f75c3109d3 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -321,8 +321,8 @@ public: // Use templates files to crate packets. if (use_templates) { tc.initPacketTemplates(); - ASSERT_GT(tc.getTemplateBuffer(0).size(), 0); - ASSERT_GT(tc.getTemplateBuffer(1).size(), 0); + ASSERT_NO_THROW(tc.getTemplateBuffer(0)); + ASSERT_NO_THROW(tc.getTemplateBuffer(1)); } // Incremental transaction id generator will generate @@ -384,8 +384,8 @@ public: // Use templates files to crate packets. if (use_templates) { tc.initPacketTemplates(); - ASSERT_GT(tc.getTemplateBuffer(0).size(), 0); - ASSERT_GT(tc.getTemplateBuffer(1).size(), 0); + ASSERT_NO_THROW(tc.getTemplateBuffer(0)); + ASSERT_NO_THROW(tc.getTemplateBuffer(1)); } // Incremental transaction id generator will generate @@ -720,14 +720,14 @@ TEST_F(TestControlTest, Packet4) { ASSERT_NO_THROW(tc.setDefaults4(sock, pkt4)); // Validate that packet has been setup correctly. EXPECT_EQ(loopback_iface, pkt4->getIface()); - EXPECT_EQ(sock.getIfIndex(), pkt4->getIndex()); + EXPECT_EQ(sock.ifindex_, pkt4->getIndex()); EXPECT_EQ(DHCP4_CLIENT_PORT, pkt4->getLocalPort()); EXPECT_EQ(DHCP4_SERVER_PORT, pkt4->getRemotePort()); EXPECT_EQ(1, pkt4->getHops()); EXPECT_EQ(asiolink::IOAddress("255.255.255.255"), pkt4->getRemoteAddr()); - EXPECT_EQ(asiolink::IOAddress(sock.getAddress()), pkt4->getLocalAddr()); - EXPECT_EQ(asiolink::IOAddress(sock.getAddress()), pkt4->getGiaddr()); + EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getLocalAddr()); + EXPECT_EQ(asiolink::IOAddress(sock.addr_), pkt4->getGiaddr()); } else { std::cout << "Unable to find the loopback interface. Skip test. " << std::endl; @@ -753,10 +753,10 @@ TEST_F(TestControlTest, Packet6) { ASSERT_NO_THROW(tc.setDefaults6(sock, pkt6)); // Validate if parameters have been set correctly. EXPECT_EQ(loopback_iface, pkt6->getIface()); - EXPECT_EQ(sock.getIfIndex(), pkt6->getIndex()); + EXPECT_EQ(sock.ifindex_, pkt6->getIndex()); EXPECT_EQ(DHCP6_CLIENT_PORT, pkt6->getLocalPort()); EXPECT_EQ(DHCP6_SERVER_PORT, pkt6->getRemotePort()); - EXPECT_EQ(sock.getAddress(), pkt6->getLocalAddr()); + EXPECT_EQ(sock.addr_, pkt6->getLocalAddr()); EXPECT_EQ(asiolink::IOAddress("FF05::1:3"), pkt6->getRemoteAddr()); } else { std::cout << "Unable to find the loopback interface. Skip test. " From 5585299f3e340017f57307bbf9568bb98931279f Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 4 Sep 2012 17:23:09 +0200 Subject: [PATCH 097/148] [1959] Minor change in checkExitConditions. --- tests/tools/perfdhcp/test_control.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 6e7fa05654..446de81c3b 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -149,7 +149,7 @@ TestControl::checkExitConditions() const { } } // Check if we reached maximum number REQUEST packets. - if (options.getNumRequests().size() == 2) { + if (options.getNumRequests().size() > 1) { if (options.getIpVersion() == 4) { if (stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) >= options.getNumRequests()[1]) { @@ -185,7 +185,7 @@ TestControl::checkExitConditions() const { } } // Check if we reached maximum number of drops of ACK/REPLY packets. - if (options.getMaxDrop().size() == 2) { + if (options.getMaxDrop().size() > 1) { if (options.getIpVersion() == 4) { if (stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) >= options.getMaxDrop()[1]) { @@ -226,7 +226,7 @@ TestControl::checkExitConditions() const { } } // Check if we reached maximum drops percentage of ACK/REPLY packets. - if (options.getMaxDropPercentage().size() == 2) { + if (options.getMaxDropPercentage().size() > 1) { if (options.getIpVersion() == 4) { if ((stats_mgr4_->getSentPacketsNum(StatsMgr4::XCHG_RA) > 10) && ((100. * stats_mgr4_->getDroppedPacketsNum(StatsMgr4::XCHG_RA) / From 7a60b5784ca9ccda3e18c740b8ff26edabbf4732 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Tue, 4 Sep 2012 20:19:55 +0100 Subject: [PATCH 098/148] [2143] Editorial changes to layout and language --- tests/tools/dhcp-ubench/dhcp-perf-guide.html | 182 +++++----- tests/tools/dhcp-ubench/dhcp-perf-guide.xml | 356 ++++++++++--------- 2 files changed, 274 insertions(+), 264 deletions(-) diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.html b/tests/tools/dhcp-ubench/dhcp-perf-guide.html index 0fc4a617bf..08475d323b 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.html +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.html @@ -1,69 +1,71 @@ -DHCP Performance Guide

    DHCP Performance Guide

    Tomasz Mrugalski

    This is a companion document for BIND 10 version - 20120817.

    Abstract

    BIND 10 is a framework that features Domain Name System - (DNS) suite and Dynamic Host Configuration Protocol (DHCP) - servers with development managed by Internet Systems Consortium (ISC). +DHCP Performance Guide

    DHCP Performance Guide

    Tomasz Mrugalski

    This is a companion document for BIND 10 version + 20120405.

    Abstract

    BIND 10 is a framework that features Domain Name System + (DNS) and Dynamic Host Configuration Protocol (DHCP) + software with development managed by Internet Systems Consortium (ISC). This document describes various aspects of DHCP performance, measurements and tuning. It covers BIND 10 DHCP (codename Kea), existing ISC DHCP4 software, perfdhcp (a DHCP performance - measurement tool) and other related topics.


    Preface

    Table of Contents

    1. Acknowledgements

    1. Acknowledgements

    ISC would like to acknowledge generous support for + measurement tool) and other related topics.


    Preface

    Table of Contents

    1. Acknowledgements

    1. Acknowledgements

    ISC would like to acknowledge generous support for BIND 10 development of DHCPv4 and DHCPv6 components provided by Comcast.

    Chapter 1. Introduction

    - This document is in its early stages of development. It is - expected to grow significantly in a near future. It will + This document is in the early stages of development. It is + expected to grow significantly in the near future. It will cover topics like database backend perfomance measurements, - pros an cons of various optimization techniques and - tools. + tools, and the pros an cons of various optimization techniques.

    Chapter 2. ISC DHCP 4.x

    TODO: Write something about ISC DHCP4 here. -

    Chapter 3. Kea

    -

    3.1. Backend performance evaluation

    +

    3.1. Backend performance evaluation

    Kea will support several different database backends, using both popular databases (like MySQL or SQLite) and - custom-developed solutions (like in-memory database). BIND 10 - source code features set of performance microbenchmarks. - These are small tools written in C/C++ that simulate expected + custom-developed solutions (such as an in-memory database). + To aid in the choice of backend, the BIND 10 + source code features a set of performance microbenchmarks. + Written in C/C++, these are small tools that simulate expected DHCP server behaviour and evaluate the performance of - considered databases. As implemented benchmarks are not really + considered databases. As implemented, the benchmarks are not really simulating DHCP operation, but rather use set of primitives - that can be used by a real server, they are called + that can be used by a real server. For this reason, they are called micro-benchmarks.

    Although there are many operations and data types that server could store in a database, the most frequently used data - type is lease information. Although lease information for IPv4 - and IPv6 differs slightly, it is expected that the performance + type is lease information. Although the information held for IPv4 + and IPv6 leases differs slightly, it is expected that the performance differences will be minimal between IPv4 and IPv6 lease operations. - Therefore each test uses lease4 table for performance measurements. + Therefore each test uses the lease4 table (in which IPv4 leases are stored) + for performance measurements.

    All benchmarks are implemented as single threaded applications that take advantage of a single database connection.

    Those benchmarks are stored in tests/tools/dhcp-ubench - directory. This directory contains simplified prototypes for - various DB back-ends that are planned or considered as a - backend engine for BIND10 DHCP. Athough trivial now, they are + directory of the BIND 10 source tree. This directory contains simplified prototypes for + the various database back-ends that are planned or considered as a + possibly for BIND10 DHCP. Athough trivial now, the benchmarks are expected to evolve into useful tools that will allow users to measure performance in their specific environment.

    Currently the following benchmarks are implemented: -

    • in memory+flat file

    • SQLite

    • MySQL

    +

    • In memory + flat file

    • SQLite

    • MySQL

    - As they require additional (sometimes heavy) dependencies, they are not - built by default. Actually, their build system is completely separated. - It will be eventually merged with the main BIND10 makefile system, but + As the benchmarks require additional (sometimes heavy) dependencies, they are not + built by default. Actually, their build system is completely separate from that + of the rest of BIND 10. + It is anticipated that they will be eventually merged into the rest of BIND 10, but that is a low priority for now.

    All benchmarks will follow the same pattern: -

    1. prepare operation (connect to a database, create a file etc.)

    2. Measure timestamp 0

    3. Commit new lease4 (repeated X times)

    4. Measure timestamp 1

    5. Search for random lease4 (repeated X times)

    6. Measure timestamp 2

    7. Update existing lease4 (repeated X times)

    8. Measure timestamp 3

    9. Delete existing lease4 (repeated X times)

    10. Measure timestamp 4

    11. Print out statistics, based on X and measured timestamps.

    +

    1. Prepare operation (connect to a database, create a file etc.)

    2. Measure timestamp 0

    3. Commit new lease4 record (repeated N times)

    4. Measure timestamp 1

    5. Search for random lease4 record (repeated N times)

    6. Measure timestamp 2

    7. Update existing lease4 record (repeated N times)

    8. Measure timestamp 3

    9. Delete existing lease4 record (repeated N times)

    10. Measure timestamp 4

    11. Print out statistics, based on N and measured timestamps.

    Although this approach does not attempt to simulate actual DHCP server - operation that has mix of all steps intervening, it answers the - questions about basic database strenghts and weak points. In particular - it can show what is the impact of specific DB optimizations, like + operation that has mix of all steps, it answers the + questions about basic database strengths and weak points. In particular + it can show what is the impact of specific database optimizations, such as changing engine, optimizing for writes/reads etc.

    - The framework attempts to do the same amount of operations for every + The framework attempts to do the same amount of work for every backend thus allowing fair complarison between them. -

    3.2. MySQL backend

    MySQL backend requires MySQL client development libraries. It uses - mysql_config tool (that works similar to pkg-config) to discover required +

    3.2. MySQL backend

    The MySQL backend requires the MySQL client development libraries. It uses + the mysql_config tool (similar to pkg-config) to discover required compilation and linking options. To install required packages on Ubuntu, use the following command: @@ -71,27 +73,27 @@ Make sure that MySQL server is running. Make sure that you have your setup configured so there is a user that is able to modify used database.

    Before running tests, you need to initialize your database. You can - use mysql.schema script for that purpose. WARNING: It will drop existing - Kea database. Do not run this on your production server. Assuming your - MySQL user is kea, you can initialize your test database by: + use mysql.schema script for that purpose.

    WARNING: It will drop existing + Kea database. Do not run this on your production server.

    Assuming your + MySQL user is "kea", you can initialize your test database by:

    $ mysql -u kea -p < mysql.schema

    -

    After database is initialized, you are ready to run the test: +

    After the database is initialized, you are ready to run the test:

    $ ./mysql_ubench

    or -

    $ ./mysql_ubench > results->mysql.txt

    +

    $ ./mysql_ubench > results-mysql.txt

    Redirecting output to a file is important, because for each operation there is a single character printed to show progress. If you have a slow - terminal, this may considerably affect test perfromance. On the other hand, - printing something after each operation is required, as poor DB setting - may slow down operations to around 20 per second. Observant user is expected - to note that initial dots are printed too slowly and abort the test.

    Currently all default parameters are hardcoded. Default values can be - overwritten using command line switches. Although all benchmarks take - the same list of parameters, some of them are specific to a given backend - type. To get a list of supported parameters, run your benchmark with -h option: + terminal, this may considerably affect test performance. On the other hand, + printing something after each operation is required as poor database settings + may slow down operations to around 20 per second. (The observant user is expected + to note that the initial dots are printed too slowly and abort the test.)

    Currently all default parameters are hardcoded. Default values can be + overridden using command line switches. Although all benchmarks take + the same list of parameters, some of them are specific to a given backend. + To get a list of supported parameters, run the benchmark with the "-h" option:

    $ ./mysql_ubench -h
     This is a benchmark designed to measure expected performance
    @@ -111,20 +113,20 @@ Possible command-line parameters:
      -c yes|no - should compiled statements be used (MySQL only)
     

    -

    3.2.1. MySQL tweaks

    One parameter that has huge impact on performance is a a backend engine. +

    3.2.1. MySQL tweaks

    One parameter that has huge impact on performance is the choice of backend engine. You can get a list of engines of your MySQL implementation by using

    > show engines;

    in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench uses use MyISAM for synchronous mode and InnoDB for asynchronous. Please use - '-s 0|1' to choose whether you want synchronous or asynchronous operations.

    Another parameter that affects performance are precompiled statements. + '-s yes|no' to choose whether you want synchronous or asynchronous operations.

    Another parameter that affects performance are precompiled statements. In a basic approach, the actual SQL query is passed as a text string that is then parsed by the database engine. Alternative is a so called precompiled statement. In this approach the SQL query is compiled an specific values are being bound to it. In the next iteration the query remains the same, only bound values are changing (e.g. searching for a different address). Usage of basic or precompiled - statements is controlled with '-c 0|1'.

    3.3. SQLite-ubench

    SQLite backend requires both sqlite3 development and run-time package. Their + statements is controlled with '-c no|yes'.

    3.3. SQLite-ubench

    The SQLite backend requires both the sqlite3 development and run-time packages. Their names may vary from system to system, but on Ubuntu 12.04 they are called sqlite3 libsqlite3-dev. To install them, use the following command: @@ -140,33 +142,33 @@ Possible command-line parameters: or

    > ./sqlite_ubench > results-sqlite.txt

    3.3.1. SQLite tweaks

    To modify default sqlite_ubench parameters, command line - switches can be used. Currently supported parameters are + switches can be used. The currently supported switches are (default values specified in brackets): -

    1. -f filename - name of the database file ("sqlite.db")

    2. -n num - number of iterations (100)

    3. -s yes|no - should the operations be performend in synchronous (yes) +

      1. -f filename - name of the database file ("sqlite.db")

      2. -n num - number of iterations (100)

      3. -s yes|no - should the operations be performed in a synchronous (yes) or asynchronous (no) manner (yes)

      4. -v yes|no - verbose mode. Should the test print out progress? (yes)

      5. -c yes|no - precompiled statements. Should the SQL statements be precompiled?

      SQLite can run in asynchronous or synchronous mode. This - mode can be controlled by using sync parameter. It is set - using (PRAGMA synchronous = ON or OFF).

      Another tweakable feature is journal mode. It can be + mode can be controlled by using "synchronous" parameter. It is set + using the SQLite command:

      PRAGMA synchronous = ON|OFF

      Another tweakable feature is journal mode. It can be turned to several modes of operation. Its value can be modified in SQLite_uBenchmark::connect(). See http://www.sqlite.org/pragma.html#pragma_journal_mode for detailed explanantion.

      sqlite_bench supports precompiled statements. Please use - '-c 0|1' to define which should be used: basic SQL query (0) or - precompiled statement (1).

    3.4. memfile-ubench

    Memfile backend is custom developed prototype backend that - somewhat mimics operation of ISC DHCP4. It uses in-memory + '-c no|yes' to define which should be used: basic SQL query (no) or + precompiled statement (yes).

    3.4. memfile-ubench

    The memfile backend is a custom backend that + somewhat mimics operation of ISC DHCP4. It implements in-memory storage using standard C++ and boost mechanisms (std::map and boost::shared_ptr<>). All database changes are also - written to a lease file. That file is strictly write-only. This + written to a lease file, which is strictly write-only. This approach takes advantage of the fact that simple append is faster than edition with potential whole file relocation.

    3.4.1. memfile tweaks

    To modify default memfile_ubench parameters, command line - switches can be used. Currently supported parameters are + switches can be used. Currently supported switches are (default values specified in brackets): -

    1. -f filename - name of the database file ("dhcpd.leases")

    2. -n num - number of iterations (100)

    3. -s yes|no - should the operations be performend in synchronous (yes) +

      1. -f filename - name of the database file ("dhcpd.leases")

      2. -n num - number of iterations (100)

      3. -s yes|no - should the operations be performend in a synchronous (yes) or asynchronous (no) manner (yes)

      4. -v yes|no - verbose mode. Should the test print out progress? (yes)

      memfile can run in asynchronous or synchronous mode. This mode can be controlled by using sync parameter. It uses fflush() and fsync() in synchronous mode to make sure that - data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, + data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    @@ -175,19 +177,19 @@ OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
     compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
     MySQL version: 5.5.24
     SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e

    -

    Benchmarks were run without using precompiled statements. - The code was compiled wit -O0 flag (no code optimizations). - Each run was executed once.

    Benchmarks were run in two series: synchronous and +

    The benchmarks were run without using precompiled statements. + The code was compiled with the -O0 flag (no code optimizations). + Each run was executed once.

    Two series of measures were made, synchronous and asynchronous. As those modes offer radically different - performances, synchronous mode was conducted for 1000 (one - thousand) repetitions and asynchronous mode was conducted for - 100000 (hundred thousand) repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreateSearchUpdateDeleteAverage
    MySQL100031.603978s 0.116612s27.964191s27.695209s21.844998s
    SQLite100061.421356s 0.033283s59.476638s56.034150s44.241357s
    memfile100038.223757s 0.000817s38.041153s38.017293s28.570755s

    Following parameters were measured for asynchronous mode. - MySQL and SQLite were run with 100 thousand repetitions. Memfile - was run for 1 million repetitions due to much larger performance.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL10000010.584842s10.386402s10.062384s 8.890197s 9.980956s
    SQLite100000 3.710356s 3.159129s 2.865354s 2.439406s 3.043561s
    memfile100000 1.299642s 0.039330s 1.307112s 1.277641s 0.980931s

    Presented performance results can be computed into operations per second metrics. - It should be noted that due to large differences between various operations (sometime - over 3 orders of magnitude), it is difficult to create a simple, readable chart with - that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Basic performance measurements

    Graphical representation of the basic performance results - presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, + performances, synchronous mode was conducted for one + thousand repetitions and asynchronous mode was conducted for + one hundred thousand repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00031.603978 0.11661227.96419127.69520921.844998
    SQLite1,00061.421356 0.03328359.47663856.03415044.241357
    memfile1,00038.223757 0.00081738.04115338.01729328.570755

    The following parameters were measured for asynchronous mode. + MySQL and SQLite were run with one hundred thousand repetitions. Memfile + was run for one million repetitions due to its much higher performance.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,00010.58484210.38640210.062384 8.890197 9.980956
    SQLite100,000 3.710356 3.159129 2.865354 2.439406 3.043561
    memfile1,000,000 1.299642 0.039330 1.307112 1.277641 0.980931

    The presented performance results can be converted into operations per second metrics. + It should be noted that due to large differences between various operations (sometimes + over three orders of magnitude), it is difficult to create a simple, readable chart with + that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Basic performance measurements

    Graphical representation of the basic performance results + presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    @@ -196,19 +198,19 @@ OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
     compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
     MySQL version: 5.5.24
     SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e

    -

    Benchmarks were run with precompiled statements enabled. - The code was compiled wit -Ofast flag (optimize compilation for speed). - Each run was repeated 3 times and measured values were averaged.

    Benchmarks were run in two series: synchronous and +

    The benchmarks were run with precompiled statements enabled. + The code was compiled with the -Ofast flag (optimize compilation for speed). + Each run was repeated three times and measured values were averaged.

    Again the benchmarks were run in two series, synchronous and asynchronous. As those modes offer radically different - performances, synchronous mode was conducted for 1000 (one - thousand) repetitions and asynchronous mode was conducted for - 100000 (hundred thousand) repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreateSearchUpdateDeleteAverage
    MySQL100027.887s 0.106s28.223s27.696s20.978s
    SQLite100061.299s 0.015s59.648s61.098s45.626s
    memfile100039.564s 0.000724s39.543s39.326w29.608s

    Following parameters were measured for asynchronous mode. - MySQL and SQLite were run with 100 thousand repetitions. Memfile - was run for 1 million repetitions due to much larger performance.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1000008.507s9.698s7.785s8.326s8.579s
    SQLite100000 1.562s 0.949s 1.513s 1.502s 1.382s
    memfile1000001.302s0.038s1.306s1.263s0.977s

    Presented performance results can be computed into operations per second metrics. + performances, synchronous mode was conducted for one + thousand repetitions and asynchronous mode was conducted for + one hundred thousand repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00027.887 0.10628.22327.69620.978
    SQLite1,00061.299 0.01559.64861.09845.626
    memfile1,00039.564 0.00072439.54339.32629.608

    The following parameters were measured for asynchronous mode. + MySQL and SQLite were run with one hundred thousand repetitions. Memfile + was run for one million repetitions due to its much higher performance.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,0008.5079.6987.7858.3268.579
    SQLite100,000 1.562 0.949 1.513 1.502 1.382
    memfile1,000,0001.3020.0381.3061.2630.977

    The presented performance results can be converted into operations per second metrics. It should be noted that due to large differences between various operations (sometime - over 3 orders of magnitude), it is difficult to create a simple, readable chart with - that data.

    Table 3.6. Estimated optimized performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)11754.8410311.3412845.3512010.2411730.44
    SQLite (async)64005.90105391.2966075.5166566.4375509.78
    memfile (async)76832.162636018.5676542.5079188.81717145.51
    MySQL (sync)35.869461.1035.4336.112392.12
    SQLite (sync)16.3167036.1116.7616.3716771.39
    memfile (sync)25.283460207.6125.2925.43865070.90

    Optimized performance measurements

    Graphical representation of the optimized performance - results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    + over three orders of magnitude), it is difficult to create a simple, readable chart with + the data.

    Table 3.6. Estimated optimized performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)11754.8410311.3412845.3512010.2411730.44
    SQLite (async)64005.90105391.2966075.5166566.4375509.78
    memfile (async)76832.162636018.5676542.5079188.81717145.51
    MySQL (sync)35.869461.1035.4336.112392.12
    SQLite (sync)16.3167036.1116.7616.3716771.39
    memfile (sync)25.283460207.6125.2925.43865070.90

    Optimized performance measurements

    Graphical representation of the optimized performance + results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    Improvements gained by introducing support for precompiled statements in MySQL is somewhat disappointing - between 6 and 29%. On the other hand, the improvement in SQLite is @@ -222,15 +224,15 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 STL code. The memfile backend is in some operations is almost twice as fast.

    - If synchronous operation is required the current performance + If synchronous operation is required, the current performance results are likely to be deemed inadequate. The limiting factor here is a disk access time. Even migrating to high - performance 15.000rpm disk is expected to only roughly double + performance 15,000 rpm disk is expected to only roughly double number of leases per second, compared to the current results. - The reason is that to write a file to disk, at lease 2 writes + The reason is that to write a file to disk, at least two writes are required: the new content and i-node modification of the file. The easiest way to boost synchronous performance is to - switch to SSD disks. Memory-backed RAM disks are also viable + switch to SSD disks. Memory-backed RAM disks are also a viable solution. However, care should be taken to properly engineer backup strategy for RAM disks.

    @@ -253,10 +255,10 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 translated to expected leases per second or queries per second performance by an actual server. The DHCP server must do much more than just query the database to properly process client's - message. Provided results should be considered as only rough + message. The provided results should be considered as only rough estimates. They can also be used for relative comparisons between backends. -

    3.8. Possible further optimizations

    +

    3.8. Possible further optimizations

    For basic measurements the code was compiled with -g -O0 flags. For optimized measurements the benchmarking code was compiled with -Ofast (optimize for speed). In both cases, the @@ -269,8 +271,8 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7

    Currently all operations are conducted on one by one basis. Each operation is treated as a separate - transaction. Grouping X operations together will potentially - bring almost X fold increase in synchronous operations. Such a + transaction. Grouping N operations together will potentially + bring almost N fold increase in synchronous operations. Such a feature is present in ISC DHCP4 and is called cache-threshold. Extension for this benchmark in this regard should be considered. That affects only write operations (insert, diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml index 1ddd79b4c1..f149c44ea6 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml @@ -40,8 +40,8 @@ BIND 10 is a framework that features Domain Name System - (DNS) suite and Dynamic Host Configuration Protocol (DHCP) - servers with development managed by Internet Systems Consortium (ISC). + (DNS) and Dynamic Host Configuration Protocol (DHCP) + software with development managed by Internet Systems Consortium (ISC). This document describes various aspects of DHCP performance, measurements and tuning. It covers BIND 10 DHCP (codename Kea), existing ISC DHCP4 software, perfdhcp (a DHCP performance @@ -70,11 +70,10 @@ Introduction - This document is in its early stages of development. It is - expected to grow significantly in a near future. It will + This document is in the early stages of development. It is + expected to grow significantly in the near future. It will cover topics like database backend perfomance measurements, - pros an cons of various optimization techniques and - tools. + tools, and the pros an cons of various optimization techniques. @@ -97,22 +96,24 @@ Kea will support several different database backends, using both popular databases (like MySQL or SQLite) and - custom-developed solutions (like in-memory database). BIND 10 - source code features set of performance microbenchmarks. - These are small tools written in C/C++ that simulate expected + custom-developed solutions (such as an in-memory database). + To aid in the choice of backend, the BIND 10 + source code features a set of performance microbenchmarks. + Written in C/C++, these are small tools that simulate expected DHCP server behaviour and evaluate the performance of - considered databases. As implemented benchmarks are not really + considered databases. As implemented, the benchmarks are not really simulating DHCP operation, but rather use set of primitives - that can be used by a real server, they are called + that can be used by a real server. For this reason, they are called micro-benchmarks. Although there are many operations and data types that server could store in a database, the most frequently used data - type is lease information. Although lease information for IPv4 - and IPv6 differs slightly, it is expected that the performance + type is lease information. Although the information held for IPv4 + and IPv6 leases differs slightly, it is expected that the performance differences will be minimal between IPv4 and IPv6 lease operations. - Therefore each test uses lease4 table for performance measurements. + Therefore each test uses the lease4 table (in which IPv4 leases are stored) + for performance measurements. All benchmarks are implemented as single threaded applications @@ -120,9 +121,9 @@ Those benchmarks are stored in tests/tools/dhcp-ubench - directory. This directory contains simplified prototypes for - various DB back-ends that are planned or considered as a - backend engine for BIND10 DHCP. Athough trivial now, they are + directory of the BIND 10 source tree. This directory contains simplified prototypes for + the various database back-ends that are planned or considered as a + possibly for BIND10 DHCP. Athough trivial now, the benchmarks are expected to evolve into useful tools that will allow users to measure performance in their specific environment. @@ -130,52 +131,53 @@ Currently the following benchmarks are implemented: - in memory+flat file + In memory + flat file SQLite MySQL - As they require additional (sometimes heavy) dependencies, they are not - built by default. Actually, their build system is completely separated. - It will be eventually merged with the main BIND10 makefile system, but + As the benchmarks require additional (sometimes heavy) dependencies, they are not + built by default. Actually, their build system is completely separate from that + of the rest of BIND 10. + It is anticipated that they will be eventually merged into the rest of BIND 10, but that is a low priority for now. All benchmarks will follow the same pattern: - prepare operation (connect to a database, create a file etc.) + Prepare operation (connect to a database, create a file etc.) Measure timestamp 0 - Commit new lease4 (repeated X times) + Commit new lease4 record (repeated N times) Measure timestamp 1 - Search for random lease4 (repeated X times) + Search for random lease4 record (repeated N times) Measure timestamp 2 - Update existing lease4 (repeated X times) + Update existing lease4 record (repeated N times) Measure timestamp 3 - Delete existing lease4 (repeated X times) + Delete existing lease4 record (repeated N times) Measure timestamp 4 - Print out statistics, based on X and measured timestamps. + Print out statistics, based on N and measured timestamps. Although this approach does not attempt to simulate actual DHCP server - operation that has mix of all steps intervening, it answers the - questions about basic database strenghts and weak points. In particular - it can show what is the impact of specific DB optimizations, like + operation that has mix of all steps, it answers the + questions about basic database strengths and weak points. In particular + it can show what is the impact of specific database optimizations, such as changing engine, optimizing for writes/reads etc. - The framework attempts to do the same amount of operations for every + The framework attempts to do the same amount of work for every backend thus allowing fair complarison between them.

    MySQL backend - MySQL backend requires MySQL client development libraries. It uses - mysql_config tool (that works similar to pkg-config) to discover required + The MySQL backend requires the MySQL client development libraries. It uses + the mysql_config tool (similar to pkg-config) to discover required compilation and linking options. To install required packages on Ubuntu, use the following command: @@ -185,31 +187,35 @@ configured so there is a user that is able to modify used database. Before running tests, you need to initialize your database. You can - use mysql.schema script for that purpose. WARNING: It will drop existing - Kea database. Do not run this on your production server. Assuming your - MySQL user is kea, you can initialize your test database by: + use mysql.schema script for that purpose. + + WARNING: It will drop existing + Kea database. Do not run this on your production server. + + Assuming your + MySQL user is "kea", you can initialize your test database by: $ mysql -u kea -p < mysql.schema - After database is initialized, you are ready to run the test: + After the database is initialized, you are ready to run the test: $ ./mysql_ubench or - $ ./mysql_ubench > results->mysql.txt + $ ./mysql_ubench > results-mysql.txt Redirecting output to a file is important, because for each operation there is a single character printed to show progress. If you have a slow - terminal, this may considerably affect test perfromance. On the other hand, - printing something after each operation is required, as poor DB setting - may slow down operations to around 20 per second. Observant user is expected - to note that initial dots are printed too slowly and abort the test. + terminal, this may considerably affect test performance. On the other hand, + printing something after each operation is required as poor database settings + may slow down operations to around 20 per second. (The observant user is expected + to note that the initial dots are printed too slowly and abort the test.) Currently all default parameters are hardcoded. Default values can be - overwritten using command line switches. Although all benchmarks take - the same list of parameters, some of them are specific to a given backend - type. To get a list of supported parameters, run your benchmark with -h option: + overridden using command line switches. Although all benchmarks take + the same list of parameters, some of them are specific to a given backend. + To get a list of supported parameters, run the benchmark with the "-h" option: $ ./mysql_ubench -h This is a benchmark designed to measure expected performance @@ -234,14 +240,14 @@ Possible command-line parameters:
    MySQL tweaks - One parameter that has huge impact on performance is a a backend engine. + One parameter that has huge impact on performance is the choice of backend engine. You can get a list of engines of your MySQL implementation by using > show engines; in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench uses use MyISAM for synchronous mode and InnoDB for asynchronous. Please use - '-s 0|1' to choose whether you want synchronous or asynchronous operations. + '-s yes|no' to choose whether you want synchronous or asynchronous operations. Another parameter that affects performance are precompiled statements. In a basic approach, the actual SQL query is passed as a text string that is @@ -249,14 +255,14 @@ Possible command-line parameters: statement. In this approach the SQL query is compiled an specific values are being bound to it. In the next iteration the query remains the same, only bound values are changing (e.g. searching for a different address). Usage of basic or precompiled - statements is controlled with '-c 0|1'. + statements is controlled with '-c no|yes'.
    SQLite-ubench - SQLite backend requires both sqlite3 development and run-time package. Their + The SQLite backend requires both the sqlite3 development and run-time packages. Their names may vary from system to system, but on Ubuntu 12.04 they are called sqlite3 libsqlite3-dev. To install them, use the following command: @@ -278,12 +284,12 @@ Possible command-line parameters:
    SQLite tweaks To modify default sqlite_ubench parameters, command line - switches can be used. Currently supported parameters are + switches can be used. The currently supported switches are (default values specified in brackets): -f filename - name of the database file ("sqlite.db") -n num - number of iterations (100) - -s yes|no - should the operations be performend in synchronous (yes) + -s yes|no - should the operations be performed in a synchronous (yes) or asynchronous (no) manner (yes) -v yes|no - verbose mode. Should the test print out progress? (yes) -c yes|no - precompiled statements. Should the SQL statements be precompiled? @@ -291,8 +297,10 @@ Possible command-line parameters: SQLite can run in asynchronous or synchronous mode. This - mode can be controlled by using sync parameter. It is set - using (PRAGMA synchronous = ON or OFF). + mode can be controlled by using "synchronous" parameter. It is set + using the SQLite command: + + PRAGMA synchronous = ON|OFF Another tweakable feature is journal mode. It can be turned to several modes of operation. Its value can be @@ -301,30 +309,30 @@ Possible command-line parameters: detailed explanantion. sqlite_bench supports precompiled statements. Please use - '-c 0|1' to define which should be used: basic SQL query (0) or - precompiled statement (1). + '-c no|yes' to define which should be used: basic SQL query (no) or + precompiled statement (yes).
    memfile-ubench - Memfile backend is custom developed prototype backend that - somewhat mimics operation of ISC DHCP4. It uses in-memory + The memfile backend is a custom backend that + somewhat mimics operation of ISC DHCP4. It implements in-memory storage using standard C++ and boost mechanisms (std::map and boost::shared_ptr<>). All database changes are also - written to a lease file. That file is strictly write-only. This + written to a lease file, which is strictly write-only. This approach takes advantage of the fact that simple append is faster than edition with potential whole file relocation.
    memfile tweaks To modify default memfile_ubench parameters, command line - switches can be used. Currently supported parameters are + switches can be used. Currently supported switches are (default values specified in brackets): -f filename - name of the database file ("dhcpd.leases") -n num - number of iterations (100) - -s yes|no - should the operations be performend in synchronous (yes) + -s yes|no - should the operations be performend in a synchronous (yes) or asynchronous (no) manner (yes) -v yes|no - verbose mode. Should the test print out progress? (yes) @@ -350,15 +358,15 @@ MySQL version: 5.5.24 SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e - Benchmarks were run without using precompiled statements. - The code was compiled wit -O0 flag (no code optimizations). + The benchmarks were run without using precompiled statements. + The code was compiled with the -O0 flag (no code optimizations). Each run was executed once. - Benchmarks were run in two series: synchronous and + Two series of measures were made, synchronous and asynchronous. As those modes offer radically different - performances, synchronous mode was conducted for 1000 (one - thousand) repetitions and asynchronous mode was conducted for - 100000 (hundred thousand) repetitions. + performances, synchronous mode was conducted for one + thousand repetitions and asynchronous mode was conducted for + one hundred thousand repetitions. Synchronous results (basic) @@ -374,51 +382,51 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 Backend Operations - Create - Search - Update - Delete - Average + Create [s] + Search [s] + Update [s] + Delete [s] + Average [s] MySQL - 1000 - 31.603978s - 0.116612s - 27.964191s - 27.695209s - 21.844998s + 1,000 + 31.603978 + 0.116612 + 27.964191 + 27.695209 + 21.844998 SQLite - 1000 - 61.421356s - 0.033283s - 59.476638s - 56.034150s - 44.241357s + 1,000 + 61.421356 + 0.033283 + 59.476638 + 56.034150 + 44.241357 memfile - 1000 - 38.223757s - 0.000817s - 38.041153s - 38.017293s - 28.570755s + 1,000 + 38.223757 + 0.000817 + 38.041153 + 38.017293 + 28.570755
    - Following parameters were measured for asynchronous mode. - MySQL and SQLite were run with 100 thousand repetitions. Memfile - was run for 1 million repetitions due to much larger performance. + The following parameters were measured for asynchronous mode. + MySQL and SQLite were run with one hundred thousand repetitions. Memfile + was run for one million repetitions due to its much higher performance. Asynchronous results (basic) @@ -444,41 +452,41 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 MySQL - 100000 - 10.584842s - 10.386402s - 10.062384s - 8.890197s - 9.980956s + 100,000 + 10.584842 + 10.386402 + 10.062384 + 8.890197 + 9.980956 SQLite - 100000 - 3.710356s - 3.159129s - 2.865354s - 2.439406s - 3.043561s + 100,000 + 3.710356 + 3.159129 + 2.865354 + 2.439406 + 3.043561 memfile - 100000 - 1.299642s - 0.039330s - 1.307112s - 1.277641s - 0.980931s + 1,000,000 + 1.299642 + 0.039330 + 1.307112 + 1.277641 + 0.980931
    - Presented performance results can be computed into operations per second metrics. - It should be noted that due to large differences between various operations (sometime - over 3 orders of magnitude), it is difficult to create a simple, readable chart with + The presented performance results can be converted into operations per second metrics. + It should be noted that due to large differences between various operations (sometimes + over three orders of magnitude), it is difficult to create a simple, readable chart with that data. Estimated basic performance @@ -587,15 +595,15 @@ MySQL version: 5.5.24 SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e - Benchmarks were run with precompiled statements enabled. - The code was compiled wit -Ofast flag (optimize compilation for speed). - Each run was repeated 3 times and measured values were averaged. + The benchmarks were run with precompiled statements enabled. + The code was compiled with the -Ofast flag (optimize compilation for speed). + Each run was repeated three times and measured values were averaged. - Benchmarks were run in two series: synchronous and + Again the benchmarks were run in two series, synchronous and asynchronous. As those modes offer radically different - performances, synchronous mode was conducted for 1000 (one - thousand) repetitions and asynchronous mode was conducted for - 100000 (hundred thousand) repetitions. + performances, synchronous mode was conducted for one + thousand repetitions and asynchronous mode was conducted for + one hundred thousand repetitions.
    Synchronous results (optimized) @@ -611,51 +619,51 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 Backend Operations - Create - Search - Update - Delete - Average + Create [s] + Search [s] + Update [s] + Delete [s] + Average [s] MySQL - 1000 - 27.887s - 0.106s - 28.223s - 27.696s - 20.978s + 1,000 + 27.887 + 0.106 + 28.223 + 27.696 + 20.978 SQLite - 1000 - 61.299s - 0.015s - 59.648s - 61.098s - 45.626s + 1,000 + 61.299 + 0.015 + 59.648 + 61.098 + 45.626 memfile - 1000 - 39.564s - 0.000724s - 39.543s - 39.326w - 29.608s + 1,000 + 39.564 + 0.000724 + 39.543 + 39.326 + 29.608
    - Following parameters were measured for asynchronous mode. - MySQL and SQLite were run with 100 thousand repetitions. Memfile - was run for 1 million repetitions due to much larger performance. + The following parameters were measured for asynchronous mode. + MySQL and SQLite were run with one hundred thousand repetitions. Memfile + was run for one million repetitions due to its much higher performance. Asynchronous results (optimized) @@ -681,42 +689,42 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 MySQL - 100000 - 8.507s - 9.698s - 7.785s - 8.326s - 8.579s + 100,000 + 8.507 + 9.698 + 7.785 + 8.326 + 8.579 SQLite - 100000 - 1.562s - 0.949s - 1.513s - 1.502s - 1.382s + 100,000 + 1.562 + 0.949 + 1.513 + 1.502 + 1.382 memfile - 100000 - 1.302s - 0.038s - 1.306s - 1.263s - 0.977s + 1,000,000 + 1.302 + 0.038 + 1.306 + 1.263 + 0.977
    - Presented performance results can be computed into operations per second metrics. + The presented performance results can be converted into operations per second metrics. It should be noted that due to large differences between various operations (sometime - over 3 orders of magnitude), it is difficult to create a simple, readable chart with - that data. + over three orders of magnitude), it is difficult to create a simple, readable chart with + the data. Estimated optimized performance @@ -832,15 +840,15 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 - If synchronous operation is required the current performance + If synchronous operation is required, the current performance results are likely to be deemed inadequate. The limiting factor here is a disk access time. Even migrating to high - performance 15.000rpm disk is expected to only roughly double + performance 15,000 rpm disk is expected to only roughly double number of leases per second, compared to the current results. - The reason is that to write a file to disk, at lease 2 writes + The reason is that to write a file to disk, at least two writes are required: the new content and i-node modification of the file. The easiest way to boost synchronous performance is to - switch to SSD disks. Memory-backed RAM disks are also viable + switch to SSD disks. Memory-backed RAM disks are also a viable solution. However, care should be taken to properly engineer backup strategy for RAM disks. @@ -867,7 +875,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 translated to expected leases per second or queries per second performance by an actual server. The DHCP server must do much more than just query the database to properly process client's - message. Provided results should be considered as only rough + message. The provided results should be considered as only rough estimates. They can also be used for relative comparisons between backends. @@ -891,8 +899,8 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 Currently all operations are conducted on one by one basis. Each operation is treated as a separate - transaction. Grouping X operations together will potentially - bring almost X fold increase in synchronous operations. Such a + transaction. Grouping N operations together will potentially + bring almost N fold increase in synchronous operations. Such a feature is present in ISC DHCP4 and is called cache-threshold. Extension for this benchmark in this regard should be considered. That affects only write operations (insert, From eedd7668751d8b5e3d47c8f233cf1d51e34ebd8e Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Wed, 5 Sep 2012 11:21:31 +0200 Subject: [PATCH 099/148] [master] fix for bsd/osx timeout error Check if socket has not been closed after timeout in read discussed on jabber --- src/lib/asiodns/tcp_server.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc index ed3f28cecc..3442de9ae7 100644 --- a/src/lib/asiodns/tcp_server.cc +++ b/src/lib/asiodns/tcp_server.cc @@ -161,6 +161,13 @@ TCPServer::operator()(asio::error_code ec, size_t length) { CORO_YIELD return; } + // Due to possible timeouts and other bad behaviour, after the + // timely reads are done, there is a chance the socket has + // been closed already. So before we move on to the actual + // processing, check that, and stop if so. + if (!socket_->is_open()) { + CORO_YIELD return; + } // Create an \c IOMessage object to store the query. // From edeea1792d69930f2e2aa1d5621e286e868c294b Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Wed, 5 Sep 2012 11:46:21 +0200 Subject: [PATCH 100/148] [2160] add comment about Message vars in sync_udp_server --- src/lib/asiodns/sync_udp_server.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/asiodns/sync_udp_server.cc b/src/lib/asiodns/sync_udp_server.cc index 037074a1c1..0c577f2474 100644 --- a/src/lib/asiodns/sync_udp_server.cc +++ b/src/lib/asiodns/sync_udp_server.cc @@ -114,7 +114,12 @@ SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) { return; } - // Make sure the buffers are fresh + // Make sure the buffers are fresh. Note that we don't touch query_ + // because it's supposed to be cleared in lookup_callback_. We should + // eventually even remove this member variable (and remove it from + // the lookup_callback_ interface, but until then, any callback + // implementation should be careful that it's the responsibility of + // the callback implementation. See also #2239). output_buffer_->clear(); answer_->clear(isc::dns::Message::RENDER); From 7c7d7c9120c5a8a8b7b9d324ee6733a968412750 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 5 Sep 2012 17:53:45 +0200 Subject: [PATCH 101/148] [1959] Implemented changes for 4th part of code review. --- tests/tools/perfdhcp/command_options.cc | 4 + tests/tools/perfdhcp/test_control.cc | 27 +- tests/tools/perfdhcp/test_control.h | 72 +++-- .../tests/command_options_unittest.cc | 54 +++- .../perfdhcp/tests/test_control_unittest.cc | 259 +++++++++++++----- 5 files changed, 311 insertions(+), 105 deletions(-) diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index dbb01e7d4c..8d9f02e763 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -495,6 +495,10 @@ CommandOptions::decodeDuid(const std::string& base) { } duid_template.push_back(static_cast(ui)); } + // @todo Get rid of this limitation when we manage add support + // for DUIDs other than LLT. Shorter DUIDs may be useful for + // server testing purposes. + check(duid_template.size() < 6, "DUID must be at least 6 octets long"); // Assign the new duid only if successfully generated. std::swap(duid_template, duid_template_); } diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 446de81c3b..ba8bf252bc 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -298,9 +298,9 @@ OptionPtr TestControl::factoryOptionRequestOption6(Option::Universe, uint16_t, const OptionBuffer&) { - const uint8_t buf_array[] = { - 0, D6O_NAME_SERVERS, - 0, D6O_DOMAIN_SEARCH + const uint16_t buf_array[] = { + htons(D6O_NAME_SERVERS), + htons(D6O_DOMAIN_SEARCH) }; OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options))); @@ -331,7 +331,7 @@ std::vector TestControl::generateMacAddress(uint8_t& randomized) const { CommandOptions& options = CommandOptions::instance(); uint32_t clients_num = options.getClientsNum(); - if ((clients_num == 0) || (clients_num == 1)) { + if (clients_num < 2) { return (options.getMacTemplate()); } // Get the base MAC address. We are going to randomize part of it. @@ -339,11 +339,7 @@ TestControl::generateMacAddress(uint8_t& randomized) const { if (mac_addr.size() != HW_ETHER_LEN) { isc_throw(BadValue, "invalid MAC address template specified"); } - uint32_t r = random(); - // The random number must be in the range 0..clients_num-1. This - // will guarantee that every client has exactly one random MAC - // address assigned. - r %= clients_num; + uint32_t r = macaddr_gen_->generate(); randomized = 0; // Randomize MAC address octets. for (std::vector::iterator it = mac_addr.end() - 1; @@ -889,7 +885,10 @@ TestControl::reset() { last_sent_ = send_due_; last_report_ = send_due_; transid_gen_.reset(); - transid_gen_ = TransidGeneratorPtr(new TransidGenerator()); + // Actual generators will have to be set later on because we need to + // get command line parameters first. + setTransidGenerator(NumberGeneratorPtr()); + setMacAddrGenerator(NumberGeneratorPtr()); first_packet_serverid_.clear(); interrupted_ = false; } @@ -907,8 +906,16 @@ TestControl::run() { if (options.getIpVersion() == 0) { isc_throw(InvalidOperation, "command options must be parsed before running a test"); + } else if (options.getIpVersion() == 4) { + setTransidGenerator(NumberGeneratorPtr(new SequencialGenerator())); + } else { + setTransidGenerator(NumberGeneratorPtr(new SequencialGenerator(0x00FFFFFF))); } + uint32_t clients_num = options.getClientsNum() == 0 ? + 1 : options.getClientsNum(); + setMacAddrGenerator(NumberGeneratorPtr(new SequencialGenerator(clients_num))); + // Diagnostics are command line options mainly. printDiagnostics(); // Option factories have to be registered. diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index cf83113daf..69dde67fc5 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -127,25 +127,51 @@ public: void initSocketData(); }; - /// \brief Default transaction id generator class. + /// \brief Number generator class. /// - /// This is default transaction id generator class. The member - /// function is used to generate unique transaction id value. - /// Other generator classes should derive from this one to - /// override the standard generation algorithm (e.g. unit tests - /// override this class wih algorithm that produces more predictable - /// transaction id values). - class TransidGenerator { + /// This is default numbers generator class. The member function is + /// used to generate uint32_t values. Other generator classes should + /// derive from this one to implement generation algorithms + /// (e.g. sequencial or based on random function). + class NumberGenerator { public: - /// \brief generate transaction id. + /// \brief Generate number. /// - /// \return generated transazction id value. - virtual uint32_t generate() { - return static_cast(random() % 0x00FFFFFF); - } + /// \return Generate number. + virtual uint32_t generate() = 0; }; - typedef boost::shared_ptr TransidGeneratorPtr; + /// The default generator pointer. + typedef boost::shared_ptr NumberGeneratorPtr; + + /// \brief Sequencial numbers generatorc class. + class SequencialGenerator : public NumberGenerator { + public: + /// \Constructor. + /// + /// \param range maximum number generated. If 0 is given then + /// range defaults to maximym uint32_t value. + SequencialGenerator(uint32_t range = 0xFFFFFFFF) : + NumberGenerator(), + num_(0), + range_(range) { + if (range_ == 0) { + range_ = 0xFFFFFFFF; + } + } + + /// \brief Generate number sequencialy. + /// + /// \return generated number. + virtual uint32_t generate() { + uint32_t num = num_; + num_ = (num_ + 1) % range_; + return (num); + } + private: + uint32_t num_; ///< Current number. + uint32_t range_; ///< Maximum number generated. + }; /// \brief Length of the Ethernet HW address (MAC) in bytes. /// @@ -172,11 +198,22 @@ public: /// \brief Set new transaction id generator. /// /// \param generator generator object to be used. - void setTransidGenerator(TransidGeneratorPtr& generator) { + void setTransidGenerator(const NumberGeneratorPtr& generator) { transid_gen_.reset(); transid_gen_ = generator; } + /// \brief Set new MAC address generator. + /// + /// Set numbers generator that will be used to generate various + /// MAC addresses to simulate number of clients. + /// + /// \param generator object to be used. + void setMacAddrGenerator(const NumberGeneratorPtr& generator) { + macaddr_gen_.reset(); + macaddr_gen_ = generator; + } + // We would really like following methods and members to be private but // they have to be accessible for unit-testing. Another, possibly better, // solution is to make this class friend of test class but this is not @@ -337,7 +374,7 @@ protected: /// /// \return generated transaction id. uint32_t generateTransid() { - return(transid_gen_->generate()); + return (transid_gen_->generate()); } /// \brief Returns number of exchanges to be started. @@ -738,7 +775,8 @@ private: StatsMgr4Ptr stats_mgr4_; ///< Statistics Manager 4. StatsMgr6Ptr stats_mgr6_; ///< Statistics Manager 6. - TransidGeneratorPtr transid_gen_; ///< Transaction id generator. + NumberGeneratorPtr transid_gen_; ///< Transaction id generator. + NumberGeneratorPtr macaddr_gen_; ///< Numbers generator for MAC address. /// Buffer holiding server id received in first packet dhcp::OptionBuffer first_packet_serverid_; diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index 70cb77d787..0481d28da3 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -264,39 +264,65 @@ TEST_F(CommandOptionsTest, ClientsNum) { TEST_F(CommandOptionsTest, Base) { CommandOptions& opt = CommandOptions::instance(); - process("perfdhcp -6 -b MAC=10::20::30::40::50::60 " - "-l ethx -b duiD=1AB7F5670901FF all"); uint8_t mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60 }; uint8_t duid[14] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x11, 0x1F, 0x14 }; - - // Test Mac + // Test DUID and MAC together. + EXPECT_NO_THROW(process("perfdhcp -b DUID=0101010101010101010110111F14" + " -b MAC=10::20::30::40::50::60" + " -l 127.0.0.1 all")); std::vector v1 = opt.getMacTemplate(); - ASSERT_EQ(6, v1.size()); + std::vector v2 = opt.getDuidTemplate(); + v2 = opt.getDuidTemplate(); EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); - // "3x" is invalid value in MAC address - EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"), - isc::InvalidParameter); - - // Test DUID + EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); + // Test valid DUID. EXPECT_NO_THROW( process("perfdhcp -b duid=0101010101010101010110111F14 -l 127.0.0.1 all") ); - std::vector v2 = opt.getDuidTemplate(); + ASSERT_EQ(sizeof(duid) / sizeof(uint8_t), v2.size()); EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); + // Test mix of upper/lower case letters. + EXPECT_NO_THROW(process("perfdhcp -b DuiD=0101010101010101010110111F14" + " -b Mac=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + v1 = opt.getMacTemplate(); + v2 = opt.getDuidTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + EXPECT_TRUE(std::equal(v2.begin(), v2.end(), duid)); + // Use "ether" instead of "mac". + EXPECT_NO_THROW(process("perfdhcp -b ether=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + v1 = opt.getMacTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); + // Use "ETHER" in upper case. + EXPECT_NO_THROW(process("perfdhcp -b ETHER=10::20::30::40::50::60" + " -l 127.0.0.1 all")); + v1 = opt.getMacTemplate(); + EXPECT_TRUE(std::equal(v1.begin(), v1.end(), mac)); // "t" is invalid character in DUID EXPECT_THROW(process("perfdhcp -6 -l ethx -b " - "duiD=010101010101010101t110111F14 all"), + "duid=010101010101010101t110111F14 all"), + isc::InvalidParameter); + // "3x" is invalid value in MAC address + EXPECT_THROW(process("perfdhcp -b mac=10::2::3x::4::5::6 -l ethx all"), isc::InvalidParameter); - - // Some more negative test cases // Base is not specified EXPECT_THROW(process("perfdhcp -b -l ethx all"), isc::InvalidParameter); // Typo: should be mac= instead of mc= EXPECT_THROW(process("perfdhcp -l ethx -b mc=00:01:02:03::04:05 all"), isc::InvalidParameter); + // Too short DUID (< 6). + EXPECT_THROW(process("perfdhcp -l ethx -b duid=00010203 all"), + isc::InvalidParameter); + // Odd number of digits. + EXPECT_THROW(process("perfdhcp -l ethx -b duid=000102030405060 all"), + isc::InvalidParameter); + // Too short MAC (!= 6). + EXPECT_THROW(process("perfdhcp -l ethx -b mac=00:01:02:04 all"), + isc::InvalidParameter); } TEST_F(CommandOptionsTest, DropTime) { diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index f75c3109d3..f94f6f73de 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -45,11 +46,11 @@ public: /// the default transaction id generator that generates transaction /// ids using random function. This generator will generate values /// like: 1,2,3 etc. - class IncrementalGenerator : public TestControl::TransidGenerator { + class IncrementalGenerator : public TestControl::NumberGenerator { public: /// \brief Default constructor. IncrementalGenerator() : - TransidGenerator(), + NumberGenerator(), transid_(0) { } @@ -88,7 +89,11 @@ public: using TestControl::setDefaults4; using TestControl::setDefaults6; - NakedTestControl() : TestControl() { }; + NakedTestControl() : TestControl() { + uint32_t clients_num = CommandOptions::instance().getClientsNum() == 0 ? + 1 : CommandOptions::instance().getClientsNum(); + setMacAddrGenerator(NumberGeneratorPtr(new TestControl::SequencialGenerator(clients_num))); + }; }; @@ -109,9 +114,27 @@ public: /// \brief Default Constructor TestControlTest() { } - static uint32_t generateTransidIncremental() { - static uint32_t transid(1); - return (++transid); + /// \brief Create packet template file from binary data. + /// + /// Function creates file containing data from the provided buffer + /// in hexadecimal format. + /// \param filename template file to be created. + /// \param buffer with binary datato be stored in file. + /// \return true if file creation successful. + bool createTemplateFile(const std::string& filename, + const std::vector& buf) const { + std::ofstream temp_file; + temp_file.open(filename.c_str(), ios::out | ios::trunc); + if (!temp_file.is_open()) { + return (false); + } + for (int i = 0; i < buf.size(); ++i) { + int first_digit = buf[i] / 16; + int second_digit = buf[i] % 16; + temp_file << std::hex << first_digit << second_digit << std::dec; + } + temp_file.close(); + return (true); } /// \brief Get local loopback interface name. @@ -130,14 +153,8 @@ public: for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin(); iface != ifaces.end(); ++iface) { - for (IfaceMgr::AddressCollection::const_iterator addr_it = - iface->getAddresses().begin(); - addr_it != iface->getAddresses().end(); - ++addr_it) { - if (asiolink::IOAddress("127.0.0.1").getAddress() == - addr_it->getAddress()) { - return (iface->getName()); - } + if (iface->flag_loopback_) { + return (iface->getName()); } } return (""); @@ -147,7 +164,7 @@ public: /// /// This method iterates through options provided in the buffer /// and matches them with the options specified with first parameter. - /// Options in both vectors may be layed in different order. + /// Options in both vectors may be laid in different order. /// /// \param requested_options reference buffer with options. /// \param buf test buffer with options that will be matched. @@ -168,6 +185,38 @@ public: return (matched_num); } + /// \brief Match requested DHCPv6 options in the buffer with given list. + /// + /// This method iterates through options provided in the buffer and + /// matches them with the options specified with first parameter. + /// Options in both vectors ma be laid in different order. + /// + /// \param requested_options reference buffer with options. + /// \param buf test buffer with options that will be matched. + /// \return number of options from the buffer matched with options in + /// the reference buffer or -1 if error occured. + int matchRequestedOptions6(const dhcp::OptionBuffer& requested_options, + const dhcp::OptionBuffer& buf) const { + // Sanity check. + if ((requested_options.size() % 2 != 0) || + (buf.size() % 2 != 0)) { + return -1; + } + size_t matched_num = 0; + for (size_t i = 0; i < buf.size(); i += 2) { + for (int j = 0; j < requested_options.size(); j += 2) { + uint16_t opt_i = buf[i + 1] << 8 + buf[i]; + uint16_t opt_j = buf[j + 1] << 8 + buf[j]; + if (opt_i == opt_j) { + // Requested option has been found. + ++matched_num; + break; + } + } + } + return (matched_num); + } + /// \brief Calculate the maximum vectors' mismatch position. /// /// This helper function calculates the maximum mismatch position @@ -180,22 +229,20 @@ public: /// on two last positions so the returned value will be 2 and so on. /// /// \param clients_num number of simulated clinets - /// \param randomization range - for either MAC or DUID it is 6 /// \return maximum mismatch position - int unequalOctetPosition(const int clients_num, - const size_t random_size) const { - int unequal_pos = 0; - int n = clients_num - 1; - if (n > 0) { - for (int i = 0; i < random_size; ++i) { - if (n < 256) { - unequal_pos = i + 1; - break; - } - n %= 256; - } + int unequalOctetPosition(int clients_num) const { + if (!clients_num) { + return (0); } - return (unequal_pos); + clients_num--; + + int cnt = 0; + while (clients_num) { + clients_num >>= 8; + ++cnt; + } + + return (cnt); } /// brief Test generation of mulitple DUIDs @@ -212,32 +259,32 @@ public: /// and do not change if single client is simulated. void testDuid() const { int clients_num = CommandOptions::instance().getClientsNum(); + // Initialize Test Control class. + NakedTestControl tc; // The old duid will be holding the previously generated DUID. // It will be used to compare against the new one. If we have // multiple clients we want to make sure that duids differ. - Duid old_duid(CommandOptions::instance().getDuidTemplate()); + uint8_t randomized = 0; + Duid old_duid(tc.generateDuid(randomized)); Duid new_duid(0); // total_dist shows the total difference between generated duid. // It has to be greater than zero if multiple clients are simulated. size_t total_dist = 0; + // Number of unique DUIDs. + size_t unique_duids = 0; // Holds the position if the octet on which two DUIDS can be different. // If number of clients is 256 or less it is last DUID octet (except for // single client when subsequent DUIDs have to be equal). If number of // clients is between 257 and 65536 the last two octets can differ etc. - const size_t mac_addr_size = 6; - int unequal_pos = unequalOctetPosition(clients_num, mac_addr_size); - - // Initialize Test Control class. - NakedTestControl tc; + int unequal_pos = unequalOctetPosition(clients_num); + // Keep generated DUIDs in this container. + std::list > duids; // Perform number of iterations to generate number of DUIDs. - // If single clinet is involved, try multiple times (10) and - // see if the same DUID is always generated. - for (int i = 0; i < clients_num * 10; ++i) { + for (int i = 0; i < 10 * clients_num; ++i) { if (new_duid.empty()) { new_duid = old_duid; } else { std::swap(old_duid, new_duid); - uint8_t randomized = 0; new_duid = tc.generateDuid(randomized); } // The DUID-LLT is expected to start with DUID_LLT value @@ -259,8 +306,8 @@ public: uint32_t duid_time = 0; // Pick 4 bytes of the time from generated DUID and put them // in reverse order (in DUID they are stored in network order). - for (int i = 4; i < 8; ++i) { - duid_time |= new_duid[i] << (i - 4); + for (int j = 4; j < 8; ++j) { + duid_time |= new_duid[j] << (j - 4); } // Calculate the duration since epoch time. ptime now = microsec_clock::universal_time(); @@ -288,11 +335,35 @@ public: // Mismatch may have occured on the DUID octet position // up to calculated earlier unequal_pos. ASSERT_LE(mismatch_dist, unequal_pos); + // unique will inform if tested DUID is unique. + bool unique = true; + for (std::list >::const_iterator it = + duids.begin(); + it != duids.end(); ++it) { + // DUIDs should be of the same size if we want to compare them. + ASSERT_EQ(new_duid.size(), it->size()); + // Check if DUID is unique. + if (std::equal(new_duid.begin(), new_duid.end(), it->begin())) { + unique = false; + } + } + // Expecting that DUIDs will be unique only when + // first clients-num iterations is performed. + // After that, DUIDs become non unique. + if (unique) { + ++unique_duids; + } + // For number of iterations equal to clients_num,2*clients_num + // 3*clients_num ... we have to have number of unique duids + // equal to clients_num. + if ((i != 0) && (i % clients_num == 0)) { + ASSERT_EQ(clients_num, unique_duids); + } + // Remember generated DUID. + duids.push_back(new_duid); } // If we have more than one client at least one mismatch occured. - if (clients_num > 1) { - EXPECT_GT(total_dist, 0); - } else { + if (clients_num < 2) { EXPECT_EQ(0, total_dist); } } @@ -327,10 +398,10 @@ public: // Incremental transaction id generator will generate // predictable values of transaction id for each iteration. - // This is important because we need to simulate reponses + // This is important because we need to simulate responses // from the server and use the same transaction ids as in // packets sent by client. - TestControl::TransidGeneratorPtr + TestControl::NumberGeneratorPtr generator(new NakedTestControl::IncrementalGenerator()); tc.setTransidGenerator(generator); // Socket is needed to send packets through the interface. @@ -393,7 +464,7 @@ public: // This is important because we need to simulate reponses // from the server and use the same transaction ids as in // packets sent by client. - TestControl::TransidGeneratorPtr + TestControl::NumberGeneratorPtr generator(new NakedTestControl::IncrementalGenerator()); tc.setTransidGenerator(generator); // Socket is needed to send packets through the interface. @@ -445,10 +516,14 @@ public: // octet (except for single client when subsequent MAC addresses // have to be equal). If number of clients is between 257 and 65536 // the last two octets can differ etc. - int unequal_pos = unequalOctetPosition(clients_num, old_mac.size());; - + int unequal_pos = unequalOctetPosition(clients_num); + // Number of unique MACs. + size_t unique_macs = 0; + // Initialize Test Controller. NakedTestControl tc; size_t total_dist = 0; + // Keep generated MACs in this container. + std::list > macs; // Do many iterations to generate and test MAC address values. for (int i = 0; i < clients_num * 10; ++i) { // Generate new MAC address. @@ -470,11 +545,35 @@ public: // Mismatch may have occured on the MAC address'es octet position // up to calculated earlier unequal_pos. ASSERT_LE(mismatch_dist, unequal_pos); + // unique will inform if tested DUID is unique. + bool unique = true; + for (std::list >::const_iterator it = + macs.begin(); + it != macs.end(); ++it) { + // MACs should be of the same size if we want to compare them. + ASSERT_EQ(new_mac.size(), it->size()); + // Check if MAC is unique. + if (std::equal(new_mac.begin(), new_mac.end(), it->begin())) { + unique = false; + } + } + // Expecting that MACs will be unique only when + // first clients-num iterations is performed. + // After that, MACs become non unique. + if (unique) { + ++unique_macs; + } + // For number of iterations equal to clients_num,2*clients_num + // 3*clients_num ... we have to have number of unique MACs + // equal to clients_num. + if ((i != 0) && (i % clients_num == 0)) { + ASSERT_EQ(clients_num, unique_macs); + } + // Remember generated MAC. + macs.push_back(new_mac); + } - // If we have more than one client at least one mismatch occured. - if (clients_num > 1) { - EXPECT_GT(total_dist, 0); - } else { + if (clients_num < 2) { EXPECT_EQ(total_dist, 0); } } @@ -489,6 +588,10 @@ public: } private: + /// \brief Create DHCPv4 OFFER packet. + /// + /// \param transid transaction id. + /// \return instance of the packet. boost::shared_ptr createOfferPkt4(uint32_t transid) const { boost::shared_ptr offer(new Pkt4(DHCPOFFER, transid)); @@ -504,6 +607,10 @@ private: return (offer); } + /// \brief Create DHCPv6 ADVERTISE packet. + /// + /// \param transid transaction id. + /// \return instance of the packet. boost::shared_ptr createAdvertisePkt6(uint32_t transid) const { OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA); @@ -664,10 +771,12 @@ TEST_F(TestControlTest, Options6) { // Validate the D6O_ORO (Option Request Option). OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO)); // Prepare the reference buffer with requested options. - const uint8_t requested_options[] = { - 0, D6O_NAME_SERVERS, - 0, D6O_DOMAIN_SEARCH + const uint16_t requested_options[] = { + htons(D6O_NAME_SERVERS), + htons(D6O_DOMAIN_SEARCH) }; + int requested_options_num = + sizeof(requested_options) / sizeof(requested_options[0]); OptionBuffer requested_options_ref(requested_options, requested_options + sizeof(requested_options)); @@ -677,9 +786,9 @@ TEST_F(TestControlTest, Options6) { // the same for comparison. EXPECT_EQ(requested_options_ref.size(), requested_options_buf.size()); // Check if all options in the buffer are matched with reference buffer. - size_t matched_num = matchRequestedOptions(requested_options_ref, - requested_options_buf); - EXPECT_EQ(sizeof(requested_options), matched_num); + size_t matched_num = matchRequestedOptions6(requested_options_ref, + requested_options_buf); + EXPECT_EQ(requested_options_num, matched_num); // Validate the D6O_IA_NA option. OptionPtr opt_ia_na(Option::factory(Option::V6, D6O_IA_NA)); @@ -698,7 +807,7 @@ TEST_F(TestControlTest, Options6) { EXPECT_TRUE(std::equal(opt_ia_na_ref.begin(), opt_ia_na_ref.end(), opt_ia_na_buf.begin())); - // TODO: Add more tests for IA address options. + // @todo Add more tests for IA address options. } TEST_F(TestControlTest, Packet4) { @@ -826,7 +935,8 @@ TEST_F(TestControlTest, Packet6Exchange) { // Set number of received packets equal to number of iterations. // This simulates no packet drops. bool use_templates = false; - testPkt6Exchange(iterations_num, iterations_num, use_templates, iterations_performed); + testPkt6Exchange(iterations_num, iterations_num, use_templates, + iterations_performed); // Actual number of iterations should be 10. EXPECT_EQ(10, iterations_performed); @@ -841,20 +951,40 @@ TEST_F(TestControlTest, Packet6Exchange) { // then test should be interrupted and actual number of iterations will // be 6. const int received_num = 3; - testPkt6Exchange(iterations_num, received_num, use_templates, iterations_performed); + testPkt6Exchange(iterations_num, received_num, use_templates, + iterations_performed); EXPECT_EQ(6, iterations_performed); } TEST_F(TestControlTest, PacketTemplates) { + std::vector template1(256); + std::string file1("../templates/test1.hex"); + std::vector template2(233); + std::string file2("../templates/test2.hex"); + for (int i = 0; i < template1.size(); ++i) { + template1[i] = static_cast(random() % 256); + } + for (int i = 0; i < template2.size(); ++i) { + template2[i] = static_cast(random() % 256); + } + ASSERT_TRUE(createTemplateFile(file1, template1)); + ASSERT_TRUE(createTemplateFile(file2, template2)); CommandOptions& options = CommandOptions::instance(); NakedTestControl tc; ASSERT_NO_THROW( processCmdLine("perfdhcp -l 127.0.0.1" - " -T ../templates/discover-example.hex" - " -T ../templates/request4-example.hex all") + " -T " + file1 + " -T " + file2 + " all") ); ASSERT_NO_THROW(tc.initPacketTemplates()); + TestControl::TemplateBuffer buf1; + TestControl::TemplateBuffer buf2; + ASSERT_NO_THROW(buf1 = tc.getTemplateBuffer(0)); + ASSERT_NO_THROW(buf2 = tc.getTemplateBuffer(1)); + ASSERT_EQ(template1.size(), buf1.size()); + ASSERT_EQ(template2.size(), buf2.size()); + EXPECT_TRUE(std::equal(template1.begin(), template1.end(), buf1.begin())); + EXPECT_TRUE(std::equal(template2.begin(), template2.end(), buf2.begin())); } TEST_F(TestControlTest, RateControl) { @@ -879,4 +1009,5 @@ TEST_F(TestControlTest, RateControl) { xchgs_num = tc2.getNextExchangesNum(); EXPECT_GT(xchgs_num, 0); EXPECT_LT(xchgs_num, options.getAggressivity()); + // @todo add more thorough checks for rate values. } From 9f8954c665a65233a6c697be3769f02d702a2728 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 5 Sep 2012 18:00:13 +0200 Subject: [PATCH 102/148] [1959] Fixed doxygen typos in test_control.h. --- tests/tools/perfdhcp/test_control.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 69dde67fc5..8e492af133 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -39,11 +39,11 @@ namespace perfdhcp { /// test end to end. /// /// Option factory functions are registered using -/// \ref LibDHCP::OptionFactoryRegister. Registered factory functions +/// \ref dhcp::LibDHCP::OptionFactoryRegister. Registered factory functions /// provide a way to create options of the same type in the same way. /// When new option instance is needed the corresponding factory /// function is called to create it. This is done by calling -/// \ref Option::factory with DHCP message type specified as one of +/// \ref dhcp::Option::factory with DHCP message type specified as one of /// parameters. Some of the parameters passed to factory function /// may be ignored (e.g. option buffer). class TestControl : public boost::noncopyable { @@ -147,7 +147,7 @@ public: /// \brief Sequencial numbers generatorc class. class SequencialGenerator : public NumberGenerator { public: - /// \Constructor. + /// \brief Constructor. /// /// \param range maximum number generated. If 0 is given then /// range defaults to maximym uint32_t value. @@ -382,7 +382,7 @@ protected: /// Method returns number of new exchanges to be started as soon /// as possible to satisfy expected rate. Calculation used here /// is based on current time, due time calculated with - /// \ref updateSendTime function and expected rate. + /// \ref updateSendDue function and expected rate. /// /// \return number of exchanges to be started immediately. uint64_t getNextExchangesNum() const; @@ -494,15 +494,15 @@ protected: /// valid. Ensure that it is valid prior to calling it. /// /// \param socket socket to be used. - /// \throw::BadValue if unknown message type received. - /// \throw::Unexpected if unexpected error occured. + /// \throw isc::BadValue if unknown message type received. + /// \throw isc::Unexpected if unexpected error occured. void receivePackets(const TestControlSocket& socket); /// \brief Register option factory functions for DHCPv4 /// /// Method registers option factory functions for DHCPv4. /// These functions are called to create instances of DHCPv4 - /// options. Call \ref Option::factory to invoke factory + /// options. Call \ref dhcp::Option::factory to invoke factory /// function for particular option. Don't use this function directly. /// Use \ref registerOptionFactories instead. void registerOptionFactories4() const; @@ -511,7 +511,7 @@ protected: /// /// Method registers option factory functions for DHCPv6. /// These functions are called to create instances of DHCPv6 - /// options. Call \ref Option::factory to invoke factory + /// options. Call \ref dhcp::Option::factory to invoke factory /// function for particular option. Don't use this function directly. /// Use \ref registerOptionFactories instead. void registerOptionFactories6() const; @@ -535,7 +535,7 @@ protected: /// with the following options: /// - MESSAGE_TYPE set to DHCPDISCOVER /// - PARAMETER_REQUEST_LIST with the same list of requested options - /// as described in \ref factoryRequestList. + /// as described in \ref factoryRequestList4. /// The transaction id and MAC address are randomly generated for /// the message. Range of unique MAC addresses generated depends /// on the number of clients specified from the command line. From fe103d1a3845a08dbf3d0af2bb3c17f10f78a6d7 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 5 Sep 2012 18:16:33 +0200 Subject: [PATCH 103/148] [1959] Fixed doxygen comments in CommandOptionsHelper class. --- .../perfdhcp/tests/command_options_helper.h | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/tests/tools/perfdhcp/tests/command_options_helper.h b/tests/tools/perfdhcp/tests/command_options_helper.h index 5886c1fad7..860a040fd3 100644 --- a/tests/tools/perfdhcp/tests/command_options_helper.h +++ b/tests/tools/perfdhcp/tests/command_options_helper.h @@ -29,7 +29,7 @@ namespace perfdhcp { /// This helper class can be shared between unit tests that /// need to initialize CommandOptions objects and feed it with /// specific command line. The command line can be given as a -/// string represinting program name, options and arguments. +/// string representing program name, options and arguments. /// The static method exposed by this class can be used to /// tokenize this string into array of C-strings that are later /// consumed by \ref CommandOptions::parse. The state of the @@ -39,12 +39,21 @@ namespace perfdhcp { class CommandOptionsHelper { public: + /// \brief Wrapper class for allocated argv[] array. + /// + /// This class wraps allocated char** array and ensures that memory + /// allocated for this array is freed at the end o the scope. class ArgvPtr { public: + /// \brief Constructor. + /// + /// \param argv array of C-strings. + /// \param number of C-strings in the array. ArgvPtr(char** argv, int argc) : argv_(argv), argc_(argc) { } - char** getArgv() const { return(argv_); } - int getArgc() const { return(argc_); } + /// \brief Destructor. + /// + /// Dealocates wrapped array of C-strings. ~ArgvPtr() { if (argv_ != NULL) { for(int i = 0; i < argc_; ++i) { @@ -55,11 +64,29 @@ public: } } + /// \brief Return the array of C-strings. + /// + /// \return array of C-strings. + char** getArgv() const { return (argv_); } + + /// \brief Return C-strings counter. + /// + /// \return C-strings counter. + int getArgc() const { return(argc_); } + public: - char** argv_; - int argc_; + char** argv_; ///< array of C-strings being wrapped. + int argc_; ///< number of C-strings. }; + /// \brief Parse command line provided as string. + /// + /// Method transforms the string representing command line + /// to the array of C-strings consumed by the + /// \ref CommandOptions::parse function and performs + /// parsing. + /// + /// \param cmdline command line provided as single string. static void process(const std::string& cmdline) { CommandOptions& opt = CommandOptions::instance(); int argc = 0; @@ -71,6 +98,11 @@ public: private: + /// \brief Split string to the array of C-strings. + /// + /// \param text_to_split string to be splited. + /// \param [out] num number of substrings returned. + /// \return array of C-strings created from split. static char** tokenizeString(const std::string& text_to_split, int& num) { char** results = NULL; // Tokenization with std streams @@ -100,7 +132,7 @@ private: } }; -} // namespace perfdhcp +} // namespace isc::perfdhcp } // namespace isc #endif // __COMMAND_OPTIONS_HELPER_H From f6ef8ec398f1711245c25eeb30887fe4de18641f Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 5 Sep 2012 19:04:12 +0200 Subject: [PATCH 104/148] [1959] Fixed bug in TestControlTest.Options6. --- tests/tools/perfdhcp/test_control.cc | 6 +++--- tests/tools/perfdhcp/tests/test_control_unittest.cc | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index ba8bf252bc..de7579d773 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -298,9 +298,9 @@ OptionPtr TestControl::factoryOptionRequestOption6(Option::Universe, uint16_t, const OptionBuffer&) { - const uint16_t buf_array[] = { - htons(D6O_NAME_SERVERS), - htons(D6O_DOMAIN_SEARCH) + const uint8_t buf_array[] = { + D6O_NAME_SERVERS, 0, + D6O_DOMAIN_SEARCH, 0, }; OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options))); diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index f94f6f73de..06dc3e561b 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -178,7 +178,6 @@ public: if (requested_options[j] == buf[i]) { // Requested option has been found. ++matched_num; - break; } } } @@ -205,12 +204,11 @@ public: size_t matched_num = 0; for (size_t i = 0; i < buf.size(); i += 2) { for (int j = 0; j < requested_options.size(); j += 2) { - uint16_t opt_i = buf[i + 1] << 8 + buf[i]; - uint16_t opt_j = buf[j + 1] << 8 + buf[j]; + uint16_t opt_i = buf[i + 1] << 8 + buf[i] & 0xFF; + uint16_t opt_j = requested_options[j + 1] << 8 + requested_options[j] & 0xFF; if (opt_i == opt_j) { // Requested option has been found. ++matched_num; - break; } } } @@ -771,9 +769,9 @@ TEST_F(TestControlTest, Options6) { // Validate the D6O_ORO (Option Request Option). OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO)); // Prepare the reference buffer with requested options. - const uint16_t requested_options[] = { - htons(D6O_NAME_SERVERS), - htons(D6O_DOMAIN_SEARCH) + const uint8_t requested_options[] = { + D6O_NAME_SERVERS, 0, + D6O_DOMAIN_SEARCH, 0, }; int requested_options_num = sizeof(requested_options) / sizeof(requested_options[0]); From 5b16ceda16bffe94ea993e3d3011dd4e1a701eb9 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Thu, 6 Sep 2012 11:18:51 +0100 Subject: [PATCH 105/148] [1545] Added logging to the DHCP4 server --- src/bin/dhcp4/Makefile.am | 17 +++-- src/bin/dhcp4/ctrl_dhcp4_srv.cc | 31 +++++---- src/bin/dhcp4/dhcp4_log.cc | 26 +++++++ src/bin/dhcp4/dhcp4_log.h | 59 ++++++++++++++++ src/bin/dhcp4/dhcp4_messages.mes | 109 ++++++++++++++++++++++++++++++ src/bin/dhcp4/dhcp4_srv.cc | 62 ++++++++++------- src/bin/dhcp4/main.cc | 41 ++++++----- src/bin/dhcp4/tests/Makefile.am | 2 + src/bin/dhcp4/tests/dhcp4_test.py | 56 ++++++++------- 9 files changed, 308 insertions(+), 95 deletions(-) create mode 100644 src/bin/dhcp4/dhcp4_log.cc create mode 100644 src/bin/dhcp4/dhcp4_log.h create mode 100644 src/bin/dhcp4/dhcp4_messages.mes diff --git a/src/bin/dhcp4/Makefile.am b/src/bin/dhcp4/Makefile.am index 295ab41de7..e0c97d17b8 100644 --- a/src/bin/dhcp4/Makefile.am +++ b/src/bin/dhcp4/Makefile.am @@ -12,7 +12,7 @@ endif pkglibexecdir = $(libexecdir)/@PACKAGE@ -CLEANFILES = spec_config.h +CLEANFILES = *.gcno *.gcda spec_config.h dhcp4_messages.h dhcp4_messages.cc man_MANS = b10-dhcp4.8 DISTCLEANFILES = $(man_MANS) @@ -35,11 +35,20 @@ endif spec_config.h: spec_config.h.pre $(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@ -BUILT_SOURCES = spec_config.h +dhcp4_messages.h dhcp4_messages.cc: dhcp4_messages.mes + $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/bin/dhcp4/dhcp4_messages.mes + +BUILT_SOURCES = spec_config.h dhcp4_messages.h dhcp4_messages.cc + pkglibexec_PROGRAMS = b10-dhcp4 -b10_dhcp4_SOURCES = main.cc dhcp4_srv.cc dhcp4_srv.h +b10_dhcp4_SOURCES = main.cc b10_dhcp4_SOURCES += ctrl_dhcp4_srv.cc ctrl_dhcp4_srv.h +b10_dhcp4_SOURCES += dhcp4_log.cc dhcp4_log.h +b10_dhcp4_SOURCES += dhcp4_srv.cc dhcp4_srv.h + +nodist_b10_dhcp4_SOURCES = dhcp4_messages.h dhcp4_messages.cc +EXTRA_DIST += dhcp4_messages.mes if USE_CLANGPP # Disable unused parameter warning caused by some of the @@ -47,7 +56,7 @@ if USE_CLANGPP b10_dhcp4_CXXFLAGS = -Wno-unused-parameter endif -b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la +b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/libb10-log.la diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index 724ddf2de5..128ebb57d6 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -24,17 +24,18 @@ #include #include #include +#include #include #include -using namespace std; -using namespace isc::util; -using namespace isc::dhcp; -using namespace isc::util; -using namespace isc::data; +using namespace isc::asiolink; using namespace isc::cc; using namespace isc::config; -using namespace isc::asiolink; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::log; +using namespace isc::util; +using namespace std; namespace isc { namespace dhcp { @@ -43,7 +44,8 @@ ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL; ConstElementPtr ControlledDhcpv4Srv::dhcp4ConfigHandler(ConstElementPtr new_config) { - cout << "b10-dhcp4: Received new config:" << new_config->str() << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_UPDATE) + .arg(new_config->str()); ConstElementPtr answer = isc::config::createAnswer(0, "Thank you for sending config."); return (answer); @@ -51,13 +53,13 @@ ControlledDhcpv4Srv::dhcp4ConfigHandler(ConstElementPtr new_config) { ConstElementPtr ControlledDhcpv4Srv::dhcp4CommandHandler(const string& command, ConstElementPtr args) { - cout << "b10-dhcp4: Received new command: [" << command << "], args=" - << args->str() << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_COMMAND_RECEIVED) + .arg(command).arg(args->str()); if (command == "shutdown") { if (ControlledDhcpv4Srv::server_) { ControlledDhcpv4Srv::server_->shutdown(); } else { - cout << "Server not initialized yet or already shut down." << endl; + LOG_WARN(dhcp4_logger, DHCP4_NOT_RUNNING); ConstElementPtr answer = isc::config::createAnswer(1, "Shutdown failure."); return (answer); @@ -93,10 +95,9 @@ void ControlledDhcpv4Srv::establishSession() { /// @todo: Check if session is not established already. Throw, if it is. - cout << "b10-dhcp4: my specfile is " << specfile << endl; - + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_CCSESSION_STARTING) + .arg(specfile); cc_session_ = new Session(io_service_.get_io_service()); - config_session_ = new ModuleCCSession(specfile, *cc_session_, dhcp4ConfigHandler, dhcp4CommandHandler, false); @@ -106,8 +107,8 @@ void ControlledDhcpv4Srv::establishSession() { /// control with the "select" model of the DHCP server. This is /// fully explained in \ref dhcpv4Session. int ctrl_socket = cc_session_->getSocketDesc(); - cout << "b10-dhcp4: Control session started, socket=" - << ctrl_socket << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_CCSESSION_STARTED) + .arg(ctrl_socket); IfaceMgr::instance().set_session_socket(ctrl_socket, sessionReader); } diff --git a/src/bin/dhcp4/dhcp4_log.cc b/src/bin/dhcp4/dhcp4_log.cc new file mode 100644 index 0000000000..51c18df455 --- /dev/null +++ b/src/bin/dhcp4/dhcp4_log.cc @@ -0,0 +1,26 @@ +// 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. + +/// Defines the logger used by the top-level component of b10-dhcp4. + +#include "dhcp4_log.h" + +namespace isc { +namespace dhcp { + +isc::log::Logger dhcp4_logger("dhcp4"); + +} // namespace dhcp +} // namespace isc + diff --git a/src/bin/dhcp4/dhcp4_log.h b/src/bin/dhcp4/dhcp4_log.h new file mode 100644 index 0000000000..9d05818f3f --- /dev/null +++ b/src/bin/dhcp4/dhcp4_log.h @@ -0,0 +1,59 @@ +// 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. + +#ifndef __DHCP4_LOG__H +#define __DHCP4_LOG__H + +#include +#include +#include + +namespace isc { +namespace dhcp { + +/// \brief DHCP4 Logging +/// +/// Defines the levels used to output debug messages in the non-library part of +/// the b10-dhcp4 program. Higher numbers equate to more verbose (and detailed) +/// output. + +// Debug levels used to log information during startup and shutdown. +const int DBG_DHCP4_START = DBGLVL_START_SHUT; +const int DBG_DHCP4_SHUT = DBGLVL_START_SHUT; + +// Debug level used to log setting information (such as configuration changes). +const int DBG_DHCP4_COMMAND = DBGLVL_COMMAND; + +// Trace basic operations within the code. +const int DBG_DHCP4_BASIC = DBGLVL_TRACE_BASIC; + +// Trace detailed operations, including errors raised when processing invalid +// packets. (These are not logged at severities of WARN or higher for fear +// that a set of deliberately invalid packets set to the server could overwhelm +// the logging.) +const int DBG_DHCP4_DETAIL = DBGLVL_TRACE_DETAIL; + +// This level is used to log the contents of packets received and sent. +const int DBG_DHCP4_DETAIL_DATA = DBGLVL_TRACE_DETAIL_DATA; + +/// Define the logger for the "dhcp4" module part of b10-dhcp4. We could define +/// a logger in each file, but we would want to define a common name to avoid +/// spelling mistakes, so it is just one small step from there to define a +/// module-common logger. +extern isc::log::Logger dhcp4_logger; + +} // namespace dhcp4 +} // namespace isc + +#endif // __DHCP4_LOG__H diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes new file mode 100644 index 0000000000..ec2cdbec5a --- /dev/null +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -0,0 +1,109 @@ +# 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. + +$NAMESPACE isc::dhcp + +% DHCP4_CCSESSION_STARTED control channel session started on socket %1 +A debug message issued during startup after the IP4v DHCP server has +successfully established a session with the BIND 10 control channel. + +% DHCP4_CCSESSION_STARTING starting control channel session, specfile: %1 +This debug message is issued just before the IPv4 DHCP server attempts to +establish a session with the BIND 10 control channel. + +% DHCP4_COMMAND_RECEIVED received command %1, arguments: %2 +A debug message listing the command (and possible arguments) received from the +BIND 10 control system. + +% DHCP4_CONFIG_UPDATE updated configuration received: %1 +A debug message indicating that the IPv4 DHCP server has received an updated +configuration from the BIND 10 configuration system. + +% DHCP4_NOT_RUNNING IPv4 DHCP server is not running +s warning message is issued when an attempt is made to shut down the IPv4 DHCP +server but it is not running. + +% DHCP4_OPEN_SOCKET opening sockets on port %1 +A debug message issued during startup, this indicates that the IPv4 DHCP +server is about to open sockets on the named port. + +% DHCP4_PACKET_DECLINE DECLINE packet received on interface %1 +The server has received a DECLINE packet on the specified interface. + +% DHCP4_PACKET_DISCOVER DISCOVER packet received on interface %1 +The server has received a DISCOVER packet on the specified interface. + +% DHCP4_PACKET_INFORM INFORM packet received on interface %1 +The server has received a DISCOVER packet on the specified interface. + +% DHCP4_PACKET_PARSE_FAIL failed to parse incoming packet: %1 +The server has received a packet that it is unable to interpret. The reason why +the packet is invalid is include in the message. + +% DHCP4_PACKET_RELEASE RELEASE packet received on interface %1 +The server has received a RELEASE packet on the specified interface. + +% DHCP4_PACKET_REQUEST REQUEST packet received on interface %1 +The server has received a REQUEST packet on the specified interface. + +% DHCP4_PACKET_UNKNOWN unknown packet type (%1) received on interface %2 +Debug message indicating that the server has received an unknown packet type +on the specified interface. The type code is given in the message. Note that +this message will also be output if the server receives packet which is valid, +but which should not be sent to the server (e.g. an OFFER or ACK). + +% DHCP4_PACK_FAIL failed to assemble message to be returned correctly +This error is output if the server failed to assemble the data to be returned to the client into +a valid packet. Additional messages will detail the reason. + +% DHCP4_QUERY_DATA responding with packet type %1 data is <<%2>> +A debug message listing the data returned to the client. + +% DHCP4_RESPONSE_DATA responding with packet type %1 data is <<%2>> +A debug message listing the data returned to the client. + +% DHCP4_SERVER_FAILED server failed: %1 +The IPv4 DHCP server has encountered a fatal error and is terminating. +The reason for the failure is included in the message. + +% DHCP4_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone +The server has failed to establish communication with the rest of BIND 10 +and is running in stand-alone mode. (This behavior will change once the +IPv4 DHCP server is properly integrated with the rest of BIND 10.) + +% DHCP4_SHUTDOWN server shutdown +The IPv4 DHCP server has terminated normally. + +% DHCP4_SHUTDOWN_REQUEST shutdown of server requested +This debug message indicates that a shutdown of the IPv4 server has been requested via a call +to the 'shutdown' method of the core Dhcpv4Srv object. + +% DHCP4_SRV_CONSTRUCT_ERROR error creating Dhcpv4Srv object, reason: %1 +This error message indicates that during startup, the construction of a core +component within the IPv4 DHCP server (the Dhcpv4 server object) has failed. +As a result, the server will exit. The reason for the failure is given +within the message. + +% DHCP4_STANDALONE skipping message queue, running standalone +This is a debug message indicating that the IPv4 server is running in standalone mode, not +connected to the message queue. Standalone mode is only useful during program development, +and should not be used in a production environment. + +% DHCP4_STARTING server starting +This informational message indicates that the IPv4 DHCP server has processed +any command-line switches and is starting. + +% DHCP4_START_INFO pid: %1, port: %2, verbose: %3, standalone: %4 +This is a debug message issued during the IPv4 DHCP server startup. It lists +some information about the parameters with which the server is running. diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index a86b010792..9d49c8d856 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -16,13 +16,15 @@ #include #include #include +#include #include #include -using namespace std; using namespace isc; -using namespace isc::dhcp; using namespace isc::asiolink; +using namespace isc::dhcp; +using namespace isc::log; +using namespace std; // These are hardcoded parameters. Currently this is a skeleton server that only // grants those options and a single, fixed, hardcoded lease. @@ -35,8 +37,7 @@ const std::string HARDCODED_DOMAIN_NAME = "isc.example.com"; const std::string HARDCODED_SERVER_ID = "192.0.2.1"; Dhcpv4Srv::Dhcpv4Srv(uint16_t port) { - cout << "Initialization: opening sockets on port " << port << endl; - + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port); try { // first call to instance() will create IfaceMgr (it's a singleton) // it may throw something if things go wrong @@ -47,8 +48,9 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port) { IfaceMgr::instance().openSockets4(port); setServerID(); + } catch (const std::exception &e) { - cerr << "Error during DHCPv4 server startup: " << e.what() << endl; + LOG_ERROR(dhcp4_logger, DHCP4_SRV_CONSTRUCT_ERROR).arg(e.what()); shutdown_ = true; return; } @@ -57,12 +59,11 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port) { } Dhcpv4Srv::~Dhcpv4Srv() { - cout << "b10-dhcp4: DHCPv4 server terminating." << endl; IfaceMgr::instance().closeSockets(); } void Dhcpv4Srv::shutdown() { - cout << "b10-dhcp4: DHCPv4 server shutdown." << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_SHUTDOWN_REQUEST); shutdown_ = true; } @@ -79,39 +80,43 @@ Dhcpv4Srv::run() { if (query) { try { query->unpack(); + } catch (const std::exception& e) { - /// TODO: Printout reasons of failed parsing - cout << "Failed to parse incoming packet " << endl; + // Failed to parse the packet. + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, + DHCP4_PACKET_PARSE_FAIL).arg(e.what()); continue; } + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA) + .arg(query->toText()); + switch (query->getType()) { case DHCPDISCOVER: rsp = processDiscover(query); break; + case DHCPREQUEST: rsp = processRequest(query); break; + case DHCPRELEASE: processRelease(query); break; + case DHCPDECLINE: processDecline(query); break; + case DHCPINFORM: processInform(query); break; + default: - cout << "Unknown pkt type received:" - << query->getType() << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_UNKNOWN) + .arg(query->getType()).arg(query->getIface()); } - cout << "Received message type " << int(query->getType()) << endl; - - // TODO: print out received packets only if verbose (or debug) - // mode is enabled - cout << query->toText(); - if (rsp) { if (rsp->getRemoteAddr().toText() == "0.0.0.0") { rsp->setRemoteAddr(query->getRemoteAddr()); @@ -127,12 +132,11 @@ Dhcpv4Srv::run() { rsp->setIface(query->getIface()); rsp->setIndex(query->getIndex()); - cout << "Replying with message type " - << static_cast(rsp->getType()) << ":" << endl; - cout << rsp->toText(); - cout << "----" << endl; - if (rsp->pack()) { - cout << "Packet assembled correctly." << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, + DHCP4_RESPONSE_DATA) + .arg(rsp->getType()).arg(rsp->toText()); + if (!rsp->pack()) { + LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL); } IfaceMgr::instance().send(rsp); } @@ -239,6 +243,8 @@ void Dhcpv4Srv::tryAssignLease(Pkt4Ptr& msg) { } Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) { + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_DISCOVER) + .arg(discover->getIface()); Pkt4Ptr offer = Pkt4Ptr (new Pkt4(DHCPOFFER, discover->getTransid())); @@ -252,6 +258,8 @@ Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) { } Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) { + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_REQUEST) + .arg(request->getIface()); Pkt4Ptr ack = Pkt4Ptr (new Pkt4(DHCPACK, request->getTransid())); @@ -265,16 +273,20 @@ Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) { } void Dhcpv4Srv::processRelease(Pkt4Ptr& release) { + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_RELEASE) + .arg(release->getIface()); /// TODO: Implement this. - cout << "Received RELEASE on " << release->getIface() << " interface." << endl; } void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) { + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_DECLINE) + .arg(decline->getIface()); /// TODO: Implement this. - cout << "Received DECLINE on " << decline->getIface() << " interface." << endl; } Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) { + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_INFORM) + .arg(inform->getIface()); /// TODO: Currently implemented echo mode. Implement this for real return (inform); } diff --git a/src/bin/dhcp4/main.cc b/src/bin/dhcp4/main.cc index 1087cc7fb6..70554eda43 100644 --- a/src/bin/dhcp4/main.cc +++ b/src/bin/dhcp4/main.cc @@ -14,9 +14,9 @@ #include #include -#include -#include #include +#include +#include #include using namespace std; @@ -59,11 +59,12 @@ main(int argc, char* argv[]) { switch (ch) { case 'v': verbose_mode = true; - isc::log::denabled = true; break; + case 's': stand_alone = true; break; + case 'p': try { port_number = boost::lexical_cast(optarg); @@ -78,51 +79,47 @@ main(int argc, char* argv[]) { usage(); } break; - case ':': + default: usage(); } } + // Check for extraneous parameters. + if ((argc - optind) > 0) { + usage(); + } + // 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); + LOG_INFO(dhcp4_logger, DHCP4_STARTING); + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_START_INFO) + .arg(getpid()).arg(port_number).arg(verbose_mode ? "yes" : "no") + .arg(stand_alone ? "yes" : "no" ); - cout << "b10-dhcp4: My pid=" << getpid() << ", binding to port " - << port_number << ", verbose " << (verbose_mode?"yes":"no") - << ", stand-alone=" << (stand_alone?"yes":"no") << endl; - - if (argc - optind > 0) { - usage(); - } int ret = EXIT_SUCCESS; - try { - - cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl; - - /// @todo: pass verbose to the actul server once logging is implemented ControlledDhcpv4Srv server(port_number); - if (!stand_alone) { try { server.establishSession(); } catch (const std::exception& ex) { - cerr << "Failed to establish BIND10 session. " - "Running in stand-alone mode:" << ex.what() << endl; + LOG_ERROR(dhcp4_logger, DHCP4_SESSION_FAIL).arg(ex.what()); // Let's continue. It is useful to have the ability to run // DHCP server in stand-alone mode, e.g. for testing } } else { - cout << "Skipping connection to the BIND10 msgq." << endl; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_STANDALONE); } - server.run(); + LOG_INFO(dhcp4_logger, DHCP4_SHUTDOWN); + } catch (const std::exception& ex) { - cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl; ret = EXIT_FAILURE; + LOG_FATAL(dhcp4_logger, DHCP4_SERVER_FAILED).arg(ex.what()); } return (ret); diff --git a/src/bin/dhcp4/tests/Makefile.am b/src/bin/dhcp4/tests/Makefile.am index 402af604f6..0e96d70017 100644 --- a/src/bin/dhcp4/tests/Makefile.am +++ b/src/bin/dhcp4/tests/Makefile.am @@ -47,6 +47,8 @@ if HAVE_GTEST TESTS += dhcp4_unittests dhcp4_unittests_SOURCES = ../dhcp4_srv.h ../dhcp4_srv.cc ../ctrl_dhcp4_srv.cc +dhcp4_unittests_SOURCES += ../dhcp4_log.h ../dhcp4_log.cc +dhcp4_unittests_SOURCES += ../dhcp4_messages.h ../dhcp4_messages.cc dhcp4_unittests_SOURCES += dhcp4_unittests.cc dhcp4_unittests_SOURCES += dhcp4_srv_unittest.cc dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc diff --git a/src/bin/dhcp4/tests/dhcp4_test.py b/src/bin/dhcp4/tests/dhcp4_test.py index 935bba645a..6901f4e7a7 100644 --- a/src/bin/dhcp4/tests/dhcp4_test.py +++ b/src/bin/dhcp4/tests/dhcp4_test.py @@ -29,14 +29,21 @@ class TestDhcpv4Daemon(unittest.TestCase): def setUp(self): # don't redirect stdout/stderr here as we want to print out things # during the test - pass + # + # However, we do want to set the logging lock directory to somewhere + # to which we can write - use the current working directory. We then + # set the appropriate environment variable. + lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD" + lockdir = os.getenv(lockdir_envvar) + if lockdir is None: + os.putenv(lockdir_envvar, os.getcwd()) def tearDown(self): pass def runCommand(self, params, wait=1): """ - This method runs dhcp4 and returns a touple: (returncode, stdout, stderr) + This method runs dhcp4 and returns a tuple: (returncode, stdout, stderr) """ ## @todo: Convert this into generic method and reuse it in dhcp6 @@ -79,9 +86,9 @@ class TestDhcpv4Daemon(unittest.TestCase): fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) # There's potential problem if b10-dhcp4 prints out more - # than 4k of text + # than 16kB of text try: - output = os.read(self.stdout_pipes[0], 4096) + output = os.read(self.stdout_pipes[0], 16384) except OSError: print("No data available from stdout") output = "" @@ -91,7 +98,7 @@ class TestDhcpv4Daemon(unittest.TestCase): output = "" try: - error = os.read(self.stderr_pipes[0], 4096) + error = os.read(self.stderr_pipes[0], 16384) except OSError: print("No data available on stderr") error = "" @@ -128,13 +135,13 @@ class TestDhcpv4Daemon(unittest.TestCase): print(" not that is can bind sockets correctly. Please ignore binding errors.") (returncode, output, error) = self.runCommand(["../b10-dhcp4", "-v"]) - - self.assertEqual( str(output).count("[b10-dhcp4] Initiating DHCPv4 server operation."), 1) + output_text = str(output) + str(error) + self.assertEqual(output_text.count("DHCP4_STARTING"), 1) def test_portnumber_0(self): print("Check that specifying port number 0 is not allowed.") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p', '0']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p', '0']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) @@ -145,7 +152,7 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_missing(self): print("Check that -p option requires a parameter.") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) @@ -156,7 +163,7 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_invalid1(self): print("Check that -p option is check against bogus port number (999999).") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p','999999']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p','999999']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) @@ -167,7 +174,7 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_invalid2(self): print("Check that -p option is check against bogus port number (123garbage).") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p','123garbage']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p','123garbage']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) @@ -178,28 +185,19 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_nonroot(self): print("Check that specifying unprivileged port number will work.") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-s', '-p', '10057']) - - # When invalid port number is specified, return code must not be success - # TODO: Temporarily commented out as socket binding on systems that do not have - # interface detection implemented currently fails. - # self.assertTrue(returncode == 0) - - # Check that there is an error message about invalid port number printed on stderr - self.assertEqual( str(output).count("opening sockets on port 10057"), 1) + # Check that there is a message about running with an unprivileged port + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-s', '-p', '10057']) + output_text = str(output) + str(error) + self.assertEqual(output_text.count("DHCP4_OPEN_SOCKET opening sockets on port 10057"), 1) def test_skip_msgq(self): print("Check that connection to BIND10 msgq can be disabled.") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-s', '-p', '10057']) - - # When invalid port number is specified, return code must not be success - # TODO: Temporarily commented out as socket binding on systems that do not have - # interface detection implemented currently fails. - # self.assertTrue(returncode == 0) - - # Check that there is an error message about invalid port number printed on stderr - self.assertEqual( str(output).count("Skipping connection to the BIND10 msgq."), 1) + # Check that the system outputs a message on one of its streams about running + # standalone. + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-s', '-p', '10057']) + output_text = str(output) + str(error) + self.assertEqual(output_text.count("DHCP4_STANDALONE"), 1) if __name__ == '__main__': unittest.main() From 58131685191d678f16320f532d86ddc2a90211ce Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 6 Sep 2012 12:24:23 +0200 Subject: [PATCH 106/148] [1959] Small fix in logical operator. --- tests/tools/perfdhcp/test_control.cc | 2 +- tests/tools/perfdhcp/tests/test_control_unittest.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index de7579d773..ef970a7948 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -278,7 +278,7 @@ TestControl::factoryIana6(Option::Universe, uint16_t, // @todo allow different values of T1, T2 and IAID. const uint8_t buf_array[] = { 0, 0, 0, 1, // IAID = 1 - 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600 + 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400 }; OptionBuffer buf_ia_na(buf_array, buf_array + sizeof(buf_array)); diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index 06dc3e561b..e5dbaf12a2 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -795,7 +795,7 @@ TEST_F(TestControlTest, Options6) { // Every IA_NA option is expected to start with this sequence. const uint8_t opt_ia_na_array[] = { 0, 0, 0, 1, // IAID = 1 - 0, 0, 3600 >> 8, 3600 && 0xff, // T1 = 3600 + 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400 }; OptionBuffer opt_ia_na_ref(opt_ia_na_array, From d06ad334dd0e8005172025cfb85409d4d1ccc996 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Thu, 6 Sep 2012 12:58:17 +0100 Subject: [PATCH 107/148] [1545] Simplify code for printing the type of packet received --- src/bin/dhcp4/dhcp4_messages.mes | 19 +++----- src/bin/dhcp4/dhcp4_srv.cc | 55 ++++++++++++++++------- src/bin/dhcp4/dhcp4_srv.h | 17 +++++++ src/bin/dhcp4/main.cc | 23 +++++----- src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 32 +++++++++++++ 5 files changed, 108 insertions(+), 38 deletions(-) diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index ec2cdbec5a..8f1c046deb 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -38,19 +38,14 @@ server but it is not running. A debug message issued during startup, this indicates that the IPv4 DHCP server is about to open sockets on the named port. -% DHCP4_PACKET_DECLINE DECLINE packet received on interface %1 -The server has received a DECLINE packet on the specified interface. - -% DHCP4_PACKET_DISCOVER DISCOVER packet received on interface %1 -The server has received a DISCOVER packet on the specified interface. - -% DHCP4_PACKET_INFORM INFORM packet received on interface %1 -The server has received a DISCOVER packet on the specified interface. - % DHCP4_PACKET_PARSE_FAIL failed to parse incoming packet: %1 The server has received a packet that it is unable to interpret. The reason why the packet is invalid is include in the message. +% DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3 +A debug message noting that the server has received the specified type of packet +on the specified interface. + % DHCP4_PACKET_RELEASE RELEASE packet received on interface %1 The server has received a RELEASE packet on the specified interface. @@ -67,10 +62,10 @@ but which should not be sent to the server (e.g. an OFFER or ACK). This error is output if the server failed to assemble the data to be returned to the client into a valid packet. Additional messages will detail the reason. -% DHCP4_QUERY_DATA responding with packet type %1 data is <<%2>> -A debug message listing the data returned to the client. +% DHCP4_QUERY_DATA received packet type %1, data is <<%2>> +A debug message listing the data received from the client. -% DHCP4_RESPONSE_DATA responding with packet type %1 data is <<%2>> +% DHCP4_RESPONSE_DATA responding with packet type %1, data is <<%2>> A debug message listing the data returned to the client. % DHCP4_SERVER_FAILED server failed: %1 diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 9d49c8d856..02c2c00f1c 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -39,12 +39,11 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1"; Dhcpv4Srv::Dhcpv4Srv(uint16_t port) { LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port); try { - // first call to instance() will create IfaceMgr (it's a singleton) + // First call to instance() will create IfaceMgr (it's a singleton) // it may throw something if things go wrong IfaceMgr::instance(); /// @todo: instantiate LeaseMgr here once it is imlpemented. - IfaceMgr::instance().openSockets4(port); setServerID(); @@ -87,10 +86,13 @@ Dhcpv4Srv::run() { DHCP4_PACKET_PARSE_FAIL).arg(e.what()); continue; } + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_UNKNOWN) + .arg(serverReceivedPacketName(query->getType())) + .arg(query->getType()) + .arg(query->getIface()); LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA) .arg(query->toText()); - switch (query->getType()) { case DHCPDISCOVER: rsp = processDiscover(query); @@ -113,8 +115,10 @@ Dhcpv4Srv::run() { break; default: - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_UNKNOWN) - .arg(query->getType()).arg(query->getIface()); + // Only action is to output a message if debug is enabled, + // and that will be covered by the debug statement before + // the "switch" statement. + ; } if (rsp) { @@ -243,8 +247,6 @@ void Dhcpv4Srv::tryAssignLease(Pkt4Ptr& msg) { } Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) { - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_DISCOVER) - .arg(discover->getIface()); Pkt4Ptr offer = Pkt4Ptr (new Pkt4(DHCPOFFER, discover->getTransid())); @@ -258,8 +260,6 @@ Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) { } Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) { - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_REQUEST) - .arg(request->getIface()); Pkt4Ptr ack = Pkt4Ptr (new Pkt4(DHCPACK, request->getTransid())); @@ -273,20 +273,45 @@ Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) { } void Dhcpv4Srv::processRelease(Pkt4Ptr& release) { - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_RELEASE) - .arg(release->getIface()); /// TODO: Implement this. } void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) { - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_DECLINE) - .arg(decline->getIface()); /// TODO: Implement this. } Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) { - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_INFORM) - .arg(inform->getIface()); /// TODO: Currently implemented echo mode. Implement this for real return (inform); } + +const char* +Dhcpv4Srv::serverReceivedPacketName(uint8_t type) { + static const char* DISCOVER = "DISCOVER"; + static const char* REQUEST = "REQUEST"; + static const char* RELEASE = "RELEASE"; + static const char* DECLINE = "DECLINE"; + static const char* INFORM = "INFORM"; + static const char* UNKNOWN = "UNKNOWN"; + + switch (type) { + case DHCPDISCOVER: + return (DISCOVER); + + case DHCPREQUEST: + return (REQUEST); + + case DHCPRELEASE: + return (RELEASE); + + case DHCPDECLINE: + return (DECLINE); + + case DHCPINFORM: + return (INFORM); + + default: + ; + } + return (UNKNOWN); +} diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h index dc087ff072..ce09f5313f 100644 --- a/src/bin/dhcp4/dhcp4_srv.h +++ b/src/bin/dhcp4/dhcp4_srv.h @@ -70,6 +70,23 @@ class Dhcpv4Srv : public boost::noncopyable { /// @brief Instructs the server to shut down. void shutdown(); + /// @brief Return textual type of packet received by server + /// + /// Returns the name of valid packet received by the server (e.g. DISCOVER). + /// If the packet is unknown - or if it is a valid DHCP packet but not one + /// expected to be received by the server (such as an OFFER), the string + /// "UNKNOWN" is returned. This methos is used in debug messages. + /// + /// As the operation of the method does not depend on any server state, it + /// is declared static. + /// + /// @param type DHCPv4 packet type + /// + /// @return Pointer to "const" string containing the packet name. + /// Note that this string is statically allocated and MUST NOT + /// be freed by the caller. + static const char* serverReceivedPacketName(uint8_t type); + protected: /// @brief Processes incoming DISCOVER and returns response. /// diff --git a/src/bin/dhcp4/main.cc b/src/bin/dhcp4/main.cc index 70554eda43..31f0b0251b 100644 --- a/src/bin/dhcp4/main.cc +++ b/src/bin/dhcp4/main.cc @@ -14,13 +14,15 @@ #include #include + +#include + #include #include #include -#include -using namespace std; using namespace isc::dhcp; +using namespace std; /// This file contains entry point (main() function) for standard DHCPv4 server /// component for BIND10 framework. It parses command-line arguments and @@ -37,11 +39,10 @@ const char* const DHCP4_NAME = "b10-dhcp4"; void usage() { - cerr << "Usage: b10-dhcp4 [-v]" - << endl; - cerr << "\t-v: verbose output" << endl; - cerr << "\t-s: stand-alone mode (don't connect to BIND10)" << endl; - cerr << "\t-p number: specify non-standard port number 1-65535 " + cerr << "Usage: " << DHCP4_NAME << " [-v] [-s] [-p number]" << endl; + cerr << " -v: verbose output" << endl; + cerr << " -s: stand-alone mode (don't connect to BIND10)" << endl; + cerr << " -p number: specify non-standard port number 1-65535 " << "(useful for testing only)" << endl; exit(EXIT_FAILURE); } @@ -50,10 +51,10 @@ usage() { int main(int argc, char* argv[]) { int ch; - bool verbose_mode = false; // should server be verbose? int port_number = DHCP4_SERVER_PORT; // The default. any other values are // useful for testing only. - bool stand_alone = false; // should be connect to BIND10 msgq? + bool stand_alone = false; // Should be connect to BIND10 msgq? + bool verbose_mode = false; // Should server be verbose? while ((ch = getopt(argc, argv, "vsp:")) != -1) { switch (ch) { @@ -86,7 +87,7 @@ main(int argc, char* argv[]) { } // Check for extraneous parameters. - if ((argc - optind) > 0) { + if (argc > optind) { usage(); } @@ -118,8 +119,8 @@ main(int argc, char* argv[]) { LOG_INFO(dhcp4_logger, DHCP4_SHUTDOWN); } catch (const std::exception& ex) { - ret = EXIT_FAILURE; LOG_FATAL(dhcp4_logger, DHCP4_SERVER_FAILED).arg(ex.what()); + ret = EXIT_FAILURE; } return (ret); diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc index cfc12fb844..08be95c47f 100644 --- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc @@ -271,4 +271,36 @@ TEST_F(Dhcpv4SrvTest, processInform) { delete srv; } +TEST_F(Dhcpv4SrvTest, serverReceivedPacketName) { + // Check all possible packet types + for (int itype = 0; itype < 256; ++itype) { + uint8_t type = itype; + + switch (type) { + case DHCPDECLINE: + EXPECT_STREQ("DECLINE", Dhcpv4Srv::serverReceivedPacketName(type)); + break; + + case DHCPDISCOVER: + EXPECT_STREQ("DISCOVER", Dhcpv4Srv::serverReceivedPacketName(type)); + break; + + case DHCPINFORM: + EXPECT_STREQ("INFORM", Dhcpv4Srv::serverReceivedPacketName(type)); + break; + + case DHCPRELEASE: + EXPECT_STREQ("RELEASE", Dhcpv4Srv::serverReceivedPacketName(type)); + break; + + case DHCPREQUEST: + EXPECT_STREQ("REQUEST", Dhcpv4Srv::serverReceivedPacketName(type)); + break; + + default: + EXPECT_STREQ("UNKNOWN", Dhcpv4Srv::serverReceivedPacketName(type)); + } + } +} + } // end of anonymous namespace From a146ae91a1a58be556dbb9cc4dc579a442397639 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 6 Sep 2012 08:29:07 -0500 Subject: [PATCH 108/148] [master] clarification about cache-enable discussed with vorner via jabber. --- doc/guide/bind10-guide.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index cbdad93489..3f8253fe36 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -1765,8 +1765,10 @@ can use various data source backends. answering up. The first option is cache-enable, a boolean value turning the cache on and off (off is the default). The second one, cache-zones, is a list of zone - origins to load into in-memory. Remember that zones in the data source - not listed here will not be loaded and will not be available at all. + origins to load into in-memory. Once the cache is enabled, + the zones in the data source not listed in + cache-zones will not be loaded and will + not be available at all.
    From 492842c8702c84a03d96bf345fe97a5970331366 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 6 Sep 2012 08:33:02 -0500 Subject: [PATCH 109/148] [master] BIND 10 style be consistent --- doc/guide/bind10-guide.xml | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index 3f8253fe36..51bcc42258 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -785,7 +785,7 @@ as a dependency earlier --> - Starting BIND10 with <command>bind10</command> + Starting BIND 10 with <command>bind10</command> BIND 10 provides the bind10 command which starts up the required processes. @@ -1746,7 +1746,7 @@ can use various data source backends. Each data source has several options. The first one is type, which specifies the type of data source to - use. Valid types include the ones listed below, but bind10 uses + use. Valid types include the ones listed below, but BIND 10 uses dynamically loaded modules for them, so there may be more in your case. This option is mandatory. @@ -1794,7 +1794,7 @@ can use various data source backends.
    Examples - As this is one of the more complex configurations of Bind10, + As this is one of the more complex configurations of BIND 10, we show some examples. They all assume they start with default configuration. @@ -1820,7 +1820,7 @@ can use various data source backends. > config commit Now every time the zone in the data source is changed by the - operator, Bind10 needs to be told to reload it, by + operator, the authoritative server needs to be told to reload it, by > Auth loadzone example.org You don't need to do this when the zone is modified by XfrIn, it does so automatically. @@ -2602,18 +2602,18 @@ then change those defaults with config set Resolver/forward_addresses[0]/address be deployed that facilitate communication between servers and clients. Even though principles of both DHCPv4 and DHCPv6 are somewhat similar, these are two radically different - protocols. BIND10 offers server implementations for both DHCPv4 + protocols. BIND 10 offers server implementations for both DHCPv4 and DHCPv6. This chapter is about DHCP for IPv4. For a description of the DHCPv6 server, see . The DHCPv4 server component is currently under intense development. You may want to check out BIND10 DHCP (Kea) wiki + url="http://bind10.isc.org/wiki/Kea">BIND 10 DHCP (Kea) wiki and recent posts on BIND10 + url="https://lists.isc.org/mailman/listinfo/bind10-dev">BIND 10 developers mailing list. - The DHCPv4 and DHCPv6 components in BIND10 architecture are + The DHCPv4 and DHCPv6 components in BIND 10 architecture are internally code named Kea. @@ -2631,7 +2631,7 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
    DHCPv4 Server Usage - BIND10 provides the DHCPv4 server component since December + BIND 10 provides the DHCPv4 server component since December 2011. It is a skeleton server and can be described as an early prototype that is not fully functional yet. It is mature enough to conduct first tests in lab environment, but it has @@ -2640,9 +2640,9 @@ then change those defaults with config set Resolver/forward_addresses[0]/address - b10-dhcp4 is a BIND10 component and is being - run under BIND10 framework. To add a DHCPv4 process to the set of running - BIND10 services, you can use following commands in bindctl: + b10-dhcp4 is a BIND 10 component and is being + run under BIND 10 framework. To add a DHCPv4 process to the set of running + BIND 10 services, you can use following commands in bindctl: > config add Boss/components b10-dhcp4 > config set Boss/components/b10-dhcp4/kind dispensable > config commit @@ -2792,19 +2792,19 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1"; DHCPv6 Server Dynamic Host Configuration Protocol for IPv6 (DHCPv6) is - specified in RFC3315. BIND10 provides DHCPv6 server implementation + specified in RFC3315. BIND 10 provides DHCPv6 server implementation that is described in this chapter. For a description of the DHCPv4 server implementation, see . The DHCPv6 server component is currently under intense development. You may want to check out BIND10 DHCP (Kea) wiki + url="http://bind10.isc.org/wiki/Kea">BIND 10 DHCP (Kea) wiki and recent posts on BIND10 + url="https://lists.isc.org/mailman/listinfo/bind10-dev">BIND 10 developers mailing list. - The DHCPv4 and DHCPv6 components in BIND10 architecture are + The DHCPv4 and DHCPv6 components in BIND 10 architecture are internally code named Kea. @@ -2823,7 +2823,7 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";
    DHCPv6 Server Usage - BIND10 provides the DHCPv6 server component since September + BIND 10 provides the DHCPv6 server component since September 2011. It is a skeleton server and can be described as an early prototype that is not fully functional yet. It is mature enough to conduct first tests in lab environment, but it has @@ -2832,9 +2832,9 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1"; - b10-dhcp6 is a BIND10 component and is being - run under BIND10 framework. To add a DHCPv6 process to the set of running - BIND10 services, you can use following commands in bindctl: + b10-dhcp6 is a BIND 10 component and is being + run under BIND 10 framework. To add a DHCPv6 process to the set of running + BIND 10 services, you can use following commands in bindctl: > config add Boss/components b10-dhcp6 > config set Boss/components/b10-dhcp6/kind dispensable > config commit @@ -3001,7 +3001,7 @@ const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1"; For non-Linux systems, there is currently stub implementation provided. Interface manager detects loopback interfaces only as their name (lo or lo0) can be easily predicted. - Please contact BIND10 development team if you are interested + Please contact the BIND 10 development team if you are interested in running DHCP components on systems other than Linux.
    From f6e2c9efff82b96e59b27a6eae84900e25447f39 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Thu, 6 Sep 2012 08:34:13 -0500 Subject: [PATCH 110/148] [master] capitalize some uses of SQLite3 be consistent --- doc/guide/bind10-guide.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index 51bcc42258..283119800f 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -1777,7 +1777,7 @@ can use various data source backends. As mentioned, the type used by default is sqlite3. It has single configuration option inside paramsdatabase_file, which contains the path - to the sqlite3 file containing the data. + to the SQLite3 file containing the data.
    @@ -1828,7 +1828,7 @@ can use various data source backends. Now, the last example is when there are master files we want to - serve in addition to whatever is inside the sqlite3 database. + serve in addition to whatever is inside the SQLite3 database. > config add data_sources/classes/IN > config set data_sources/classes/IN[1]/type MasterFiles @@ -1857,7 +1857,7 @@ can use various data source backends. There's also Auth/database_file configuration - variable, pointing to a sqlite3 database file. This is no longer + variable, pointing to a SQLite3 database file. This is no longer used by b10-auth, but it is left in place for now, since other modules use it. Once b10-xfrin, b10-xfrout and b10-ddns From 71555cfc1c317e6ed98f9fd231f5c62c1df10910 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Thu, 6 Sep 2012 15:40:12 +0100 Subject: [PATCH 111/148] [1545] Minor tidy-up of DHCP4 server logging code --- src/bin/dhcp4/ctrl_dhcp4_srv.cc | 12 +++++++----- src/bin/dhcp4/dhcp4_messages.mes | 16 +++------------- src/bin/dhcp4/dhcp4_srv.cc | 8 +++++--- src/bin/dhcp4/tests/dhcp4_test.py | 8 ++++---- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index 128ebb57d6..4bd3103b6b 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -13,20 +13,21 @@ // PERFORMANCE OF THIS SOFTWARE. #include + #include #include -#include +#include #include -#include +#include #include #include -#include -#include #include #include +#include #include -#include +#include +#include using namespace isc::asiolink; using namespace isc::cc; @@ -55,6 +56,7 @@ ConstElementPtr ControlledDhcpv4Srv::dhcp4CommandHandler(const string& command, ConstElementPtr args) { LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_COMMAND_RECEIVED) .arg(command).arg(args->str()); + if (command == "shutdown") { if (ControlledDhcpv4Srv::server_) { ControlledDhcpv4Srv::server_->shutdown(); diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 8f1c046deb..03a136436f 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -44,19 +44,9 @@ the packet is invalid is include in the message. % DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3 A debug message noting that the server has received the specified type of packet -on the specified interface. - -% DHCP4_PACKET_RELEASE RELEASE packet received on interface %1 -The server has received a RELEASE packet on the specified interface. - -% DHCP4_PACKET_REQUEST REQUEST packet received on interface %1 -The server has received a REQUEST packet on the specified interface. - -% DHCP4_PACKET_UNKNOWN unknown packet type (%1) received on interface %2 -Debug message indicating that the server has received an unknown packet type -on the specified interface. The type code is given in the message. Note that -this message will also be output if the server receives packet which is valid, -but which should not be sent to the server (e.g. an OFFER or ACK). +on the specified interface. Note that a packet marked as UNKNOWN may well be +a valid DHCP packet, just a type not expected by the server (e.g. it will +report a received OFFER packet as UNKNOWN). % DHCP4_PACK_FAIL failed to assemble message to be returned correctly This error is output if the server failed to assemble the data to be returned to the client into diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 02c2c00f1c..2bbc0758ef 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -86,7 +86,7 @@ Dhcpv4Srv::run() { DHCP4_PACKET_PARSE_FAIL).arg(e.what()); continue; } - LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_UNKNOWN) + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_RECEIVED) .arg(serverReceivedPacketName(query->getType())) .arg(query->getType()) .arg(query->getIface()); @@ -139,10 +139,12 @@ Dhcpv4Srv::run() { LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_RESPONSE_DATA) .arg(rsp->getType()).arg(rsp->toText()); - if (!rsp->pack()) { + + if (rsp->pack()) { + IfaceMgr::instance().send(rsp); + } else { LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL); } - IfaceMgr::instance().send(rsp); } } diff --git a/src/bin/dhcp4/tests/dhcp4_test.py b/src/bin/dhcp4/tests/dhcp4_test.py index 6901f4e7a7..3ad97c6c98 100644 --- a/src/bin/dhcp4/tests/dhcp4_test.py +++ b/src/bin/dhcp4/tests/dhcp4_test.py @@ -27,7 +27,7 @@ import fcntl class TestDhcpv4Daemon(unittest.TestCase): def setUp(self): - # don't redirect stdout/stderr here as we want to print out things + # Don't redirect stdout/stderr here as we want to print out things # during the test # # However, we do want to set the logging lock directory to somewhere @@ -152,7 +152,7 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_missing(self): print("Check that -p option requires a parameter.") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) @@ -163,7 +163,7 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_invalid1(self): print("Check that -p option is check against bogus port number (999999).") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p','999999']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p','999999']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) @@ -174,7 +174,7 @@ class TestDhcpv4Daemon(unittest.TestCase): def test_portnumber_invalid2(self): print("Check that -p option is check against bogus port number (123garbage).") - (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-v', '-p','123garbage']) + (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p','123garbage']) # When invalid port number is specified, return code must not be success self.assertTrue(returncode != 0) From 6f7afc7ded635b4f40704b334d9d3cefbd46ab55 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Thu, 6 Sep 2012 15:54:03 +0100 Subject: [PATCH 112/148] [1545] Minor wording changes to the message files --- src/bin/dhcp4/dhcp4_messages.mes | 78 +++++++++++++----------- src/bin/dhcp6/dhcp6_messages.mes | 101 +++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 37 deletions(-) create mode 100644 src/bin/dhcp6/dhcp6_messages.mes diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 03a136436f..b149b25322 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -15,47 +15,48 @@ $NAMESPACE isc::dhcp % DHCP4_CCSESSION_STARTED control channel session started on socket %1 -A debug message issued during startup after the IP4v DHCP server has +A debug message issued during startup after the IPv4 DHCP server has successfully established a session with the BIND 10 control channel. % DHCP4_CCSESSION_STARTING starting control channel session, specfile: %1 -This debug message is issued just before the IPv4 DHCP server attempts to -establish a session with the BIND 10 control channel. +This debug message is issued just before the IPv4 DHCP server attempts +to establish a session with the BIND 10 control channel. % DHCP4_COMMAND_RECEIVED received command %1, arguments: %2 -A debug message listing the command (and possible arguments) received from the -BIND 10 control system. +A debug message listing the command (and possible arguments) received +from the BIND 10 control system by the IPv4 DHCP server. % DHCP4_CONFIG_UPDATE updated configuration received: %1 -A debug message indicating that the IPv4 DHCP server has received an updated -configuration from the BIND 10 configuration system. +A debug message indicating that the IPv4 DHCP server has received an +updated configuration from the BIND 10 configuration system. % DHCP4_NOT_RUNNING IPv4 DHCP server is not running -s warning message is issued when an attempt is made to shut down the IPv4 DHCP -server but it is not running. +A warning message is issued when an attempt is made to shut down the +IPv4 DHCP server but it is not running. % DHCP4_OPEN_SOCKET opening sockets on port %1 A debug message issued during startup, this indicates that the IPv4 DHCP -server is about to open sockets on the named port. +server is about to open sockets on the specified port. % DHCP4_PACKET_PARSE_FAIL failed to parse incoming packet: %1 -The server has received a packet that it is unable to interpret. The reason why -the packet is invalid is include in the message. +The IPv4 DHCP server has received a packet that it is unable to +interpret. The reason why the packet is invalid is include in the message. % DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3 -A debug message noting that the server has received the specified type of packet -on the specified interface. Note that a packet marked as UNKNOWN may well be -a valid DHCP packet, just a type not expected by the server (e.g. it will -report a received OFFER packet as UNKNOWN). +A debug message noting that the server has received the specified type of +packet on the specified interface. Note that a packet marked as UNKNOWN +may well be a valid DHCP packet, just a type not expected by the server +(e.g. it will report a received OFFER packet as UNKNOWN). -% DHCP4_PACK_FAIL failed to assemble message to be returned correctly -This error is output if the server failed to assemble the data to be returned to the client into -a valid packet. Additional messages will detail the reason. +% DHCP4_PACK_FAIL failed to assemble response correctly +This error is output if the server failed to assemble the data to be +returned to the client into a valid packet. Additional messages will +detail the reason. -% DHCP4_QUERY_DATA received packet type %1, data is <<%2>> +% DHCP4_QUERY_DATA received packet type %1, data is <%2> A debug message listing the data received from the client. -% DHCP4_RESPONSE_DATA responding with packet type %1, data is <<%2>> +% DHCP4_RESPONSE_DATA responding with packet type %1, data is <%2> A debug message listing the data returned to the client. % DHCP4_SERVER_FAILED server failed: %1 @@ -63,32 +64,35 @@ The IPv4 DHCP server has encountered a fatal error and is terminating. The reason for the failure is included in the message. % DHCP4_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone -The server has failed to establish communication with the rest of BIND 10 -and is running in stand-alone mode. (This behavior will change once the -IPv4 DHCP server is properly integrated with the rest of BIND 10.) +The server has failed to establish communication with the rest of BIND +10 and is running in stand-alone mode. (This behavior will change once +the IPv4 DHCP server is properly integrated with the rest of BIND 10.) % DHCP4_SHUTDOWN server shutdown The IPv4 DHCP server has terminated normally. % DHCP4_SHUTDOWN_REQUEST shutdown of server requested -This debug message indicates that a shutdown of the IPv4 server has been requested via a call -to the 'shutdown' method of the core Dhcpv4Srv object. +This debug message indicates that a shutdown of the IPv4 server has +been requested via a call to the 'shutdown' method of the core Dhcpv4Srv +object. % DHCP4_SRV_CONSTRUCT_ERROR error creating Dhcpv4Srv object, reason: %1 -This error message indicates that during startup, the construction of a core -component within the IPv4 DHCP server (the Dhcpv4 server object) has failed. -As a result, the server will exit. The reason for the failure is given -within the message. +This error message indicates that during startup, the construction of a +core component within the IPv4 DHCP server (the Dhcpv4 server object) +has failed. As a result, the server will exit. The reason for the +failure is given within the message. % DHCP4_STANDALONE skipping message queue, running standalone -This is a debug message indicating that the IPv4 server is running in standalone mode, not -connected to the message queue. Standalone mode is only useful during program development, -and should not be used in a production environment. +This is a debug message indicating that the IPv4 server is running in +standalone mode, not connected to the message queue. Standalone mode +is only useful during program development, and should not be used in a +production environment. % DHCP4_STARTING server starting -This informational message indicates that the IPv4 DHCP server has processed -any command-line switches and is starting. +This informational message indicates that the IPv4 DHCP server has +processed any command-line switches and is starting. % DHCP4_START_INFO pid: %1, port: %2, verbose: %3, standalone: %4 -This is a debug message issued during the IPv4 DHCP server startup. It lists -some information about the parameters with which the server is running. +This is a debug message issued during the IPv4 DHCP server startup. +It lists some information about the parameters with which the server +is running. diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes new file mode 100644 index 0000000000..f2e6fda2c9 --- /dev/null +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -0,0 +1,101 @@ +# 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. + +$NAMESPACE isc::dhcp + +% DHCP6_CCSESSION_STARTED control channel session started on socket %1 +A debug message issued during startup after the IPv6 DHCP server has +successfully established a session with the BIND 10 control channel. + +% DHCP6_CCSESSION_STARTING starting control channel session, specfile: %1 +This debug message is issued just before the IPv6 DHCP server attempts +to establish a session with the BIND 10 control channel. + +% DHCP6_COMMAND_RECEIVED received command %1, arguments: %2 +A debug message listing the command (and possible arguments) received +from the BIND 10 control system by the IPv6 DHCP server. + +% DHCP6_CONFIG_UPDATE updated configuration received: %1 +A debug message indicating that the IPv6 DHCP server has received an +updated configuration from the BIND 10 configuration system. + +% DHCP6_NOT_RUNNING IPv6 DHCP server is not running +A warning message is issued when an attempt is made to shut down the +IPv6 DHCP server but it is not running. + +% DHCP6_NO_INTERFACES failed to detect any network interfaces +During startup the IPv6 DHCP server failed to detect any network +interfaces and is therefore shutting down. + +% DHCP6_OPEN_SOCKET opening sockets on port %1 +A debug message issued during startup, this indicates that the IPv6 DHCP +server is about to open sockets on the specified port. + +% DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet +The IPv6 DHCP server has received a packet that it is unable to interpret. + +% DHCP6_PACKET_RECEIVED %1 (type %2) packet received +A debug message noting that the server has received the specified type +of packet. Note that a packet marked as UNKNOWN may well be a valid +DHCP packet, just a type not expected by the server (e.g. it will report +a received OFFER packet as UNKNOWN). + +% DHCP6_PACK_FAIL failed to assemble response correctly +This error is output if the server failed to assemble the data to be +returned to the client into a valid packet. Additional messages will +detail the reason. + +% DHCP6_QUERY_DATA received packet length %1, data length %2, data is <%3> +A debug message listing the data received from the client or relay. + +% DHCP6_RESPONSE_DATA responding with packet type %1 data is <%2> +A debug message listing the data returned to the client. + +% DHCP6_SERVER_FAILED server failed: %1 +The IPv6 DHCP server has encountered a fatal error and is terminating. +The reason for the failure is included in the message. + +% DHCP6_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone +The server has failed to establish communication with the rest of BIND +10 and is running in stand-alone mode. (This behavior will change once +the IPv6 DHCP server is properly integrated with the rest of BIND 10.) + +% DHCP6_SHUTDOWN server shutdown +The IPv6 DHCP server has terminated normally. + +% DHCP6_SHUTDOWN_REQUEST shutdown of server requested +This debug message indicates that a shutdown of the IPv6 server has +been requested via a call to the 'shutdown' method of the core Dhcpv6Srv +object. + +% DHCP6_SRV_CONSTRUCT_ERROR error creating Dhcpv6Srv object, reason: %1 +This error message indicates that during startup, the construction of a +core component within the IPv6 DHCP server (the Dhcpv6 server object) +has failed. As a result, the server will exit. The reason for the +failure is given within the message. + +% DHCP6_STANDALONE skipping message queue, running standalone +This is a debug message indicating that the IPv6 server is running in +standalone mode, not connected to the message queue. Standalone mode +is only useful during program development, and should not be used in a +production environment. + +% DHCP6_STARTING server starting +This informational message indicates that the IPv6 DHCP server has +processed any command-line switches and is starting. + +% DHCP6_START_INFO pid: %1, port: %2, verbose: %3, standalone: %4 +This is a debug message issued during the IPv6 DHCP server startup. +It lists some information about the parameters with which the server +is running. From 9c0444c02ef367b397f6c189fdba6bab717c7ec3 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Thu, 6 Sep 2012 15:56:58 +0100 Subject: [PATCH 113/148] [1545] Add logging to the DHCPv6 server code --- src/bin/dhcp6/Makefile.am | 17 +++- src/bin/dhcp6/ctrl_dhcp6_srv.cc | 43 ++++---- src/bin/dhcp6/dhcp6_log.cc | 26 +++++ src/bin/dhcp6/dhcp6_log.h | 59 +++++++++++ src/bin/dhcp6/dhcp6_srv.cc | 119 ++++++++++++++++------ src/bin/dhcp6/dhcp6_srv.h | 18 ++++ src/bin/dhcp6/main.cc | 58 +++++------ src/bin/dhcp6/tests/Makefile.am | 7 +- src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 45 ++++++++ src/bin/dhcp6/tests/dhcp6_test.py | 49 +++++---- 10 files changed, 330 insertions(+), 111 deletions(-) create mode 100644 src/bin/dhcp6/dhcp6_log.cc create mode 100644 src/bin/dhcp6/dhcp6_log.h diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am index f711c973cf..4dec4e7da6 100644 --- a/src/bin/dhcp6/Makefile.am +++ b/src/bin/dhcp6/Makefile.am @@ -13,7 +13,7 @@ endif pkglibexecdir = $(libexecdir)/@PACKAGE@ -CLEANFILES = spec_config.h +CLEANFILES = spec_config.h dhcp6_messages.h dhcp6_messages.cc man_MANS = b10-dhcp6.8 DISTCLEANFILES = $(man_MANS) @@ -37,11 +37,20 @@ endif spec_config.h: spec_config.h.pre $(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@ -BUILT_SOURCES = spec_config.h +dhcp6_messages.h dhcp6_messages.cc: dhcp6_messages.mes + $(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/bin/dhcp6/dhcp6_messages.mes + +BUILT_SOURCES = spec_config.h dhcp6_messages.h dhcp6_messages.cc + pkglibexec_PROGRAMS = b10-dhcp6 -b10_dhcp6_SOURCES = main.cc dhcp6_srv.cc dhcp6_srv.h +b10_dhcp6_SOURCES = main.cc b10_dhcp6_SOURCES += ctrl_dhcp6_srv.cc ctrl_dhcp6_srv.h +b10_dhcp6_SOURCES += dhcp6_log.cc dhcp6_log.h +b10_dhcp6_SOURCES += dhcp6_srv.cc dhcp6_srv.h + +nodist_b10_dhcp6_SOURCES = dhcp6_messages.h dhcp6_messages.cc +EXTRA_DIST += dhcp6_messages.mes if USE_CLANGPP # Disable unused parameter warning caused by some of the @@ -49,7 +58,7 @@ if USE_CLANGPP b10_dhcp6_CXXFLAGS = -Wno-unused-parameter endif -b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la +b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 461d5f1d64..4afb2039fd 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -13,28 +13,30 @@ // PERFORMANCE OF THIS SOFTWARE. #include + #include #include -#include +#include #include -#include +#include #include #include -#include -#include #include +#include +#include #include -#include +#include +#include -using namespace std; -using namespace isc::util; -using namespace isc::dhcp; -using namespace isc::util; -using namespace isc::data; +using namespace isc::asiolink; using namespace isc::cc; using namespace isc::config; -using namespace isc::asiolink; +using namespace isc::data; +using namespace isc::dhcp; +using namespace isc::log; +using namespace isc::util; +using namespace std; namespace isc { namespace dhcp { @@ -43,7 +45,8 @@ ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL; ConstElementPtr ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) { - cout << "b10-dhcp6: Received new config:" << new_config->str() << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE) + .arg(new_config->str()); ConstElementPtr answer = isc::config::createAnswer(0, "Thank you for sending config."); return (answer); @@ -51,13 +54,14 @@ ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) { ConstElementPtr ControlledDhcpv6Srv::dhcp6CommandHandler(const string& command, ConstElementPtr args) { - cout << "b10-dhcp6: Received new command: [" << command << "], args=" - << args->str() << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_COMMAND_RECEIVED) + .arg(command).arg(args->str()); + if (command == "shutdown") { if (ControlledDhcpv6Srv::server_) { ControlledDhcpv6Srv::server_->shutdown(); } else { - cout << "Server not initialized yet or already shut down." << endl; + LOG_WARN(dhcp6_logger, DHCP6_NOT_RUNNING); ConstElementPtr answer = isc::config::createAnswer(1, "Shutdown failure."); return (answer); @@ -93,10 +97,9 @@ void ControlledDhcpv6Srv::establishSession() { /// @todo: Check if session is not established already. Throw, if it is. - cout << "b10-dhcp6: my specfile is " << specfile << endl; - + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTING) + .arg(specfile); cc_session_ = new Session(io_service_.get_io_service()); - config_session_ = new ModuleCCSession(specfile, *cc_session_, dhcp6ConfigHandler, dhcp6CommandHandler, false); @@ -106,8 +109,8 @@ void ControlledDhcpv6Srv::establishSession() { /// control with the "select" model of the DHCP server. This is /// fully explained in \ref dhcpv6Session. int ctrl_socket = cc_session_->getSocketDesc(); - cout << "b10-dhcp6: Control session started, socket=" - << ctrl_socket << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTED) + .arg(ctrl_socket); IfaceMgr::instance().set_session_socket(ctrl_socket, sessionReader); } diff --git a/src/bin/dhcp6/dhcp6_log.cc b/src/bin/dhcp6/dhcp6_log.cc new file mode 100644 index 0000000000..9816f47b03 --- /dev/null +++ b/src/bin/dhcp6/dhcp6_log.cc @@ -0,0 +1,26 @@ +// 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. + +/// Defines the logger used by the top-level component of b10-dhcp6. + +#include "dhcp6_log.h" + +namespace isc { +namespace dhcp { + +isc::log::Logger dhcp6_logger("dhcp6"); + +} // namespace dhcp +} // namespace isc + diff --git a/src/bin/dhcp6/dhcp6_log.h b/src/bin/dhcp6/dhcp6_log.h new file mode 100644 index 0000000000..8db11dbad0 --- /dev/null +++ b/src/bin/dhcp6/dhcp6_log.h @@ -0,0 +1,59 @@ +// 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. + +#ifndef __DHCP6_LOG__H +#define __DHCP6_LOG__H + +#include +#include +#include + +namespace isc { +namespace dhcp { + +/// \brief DHCP6 Logging +/// +/// Defines the levels used to output debug messages in the non-library part of +/// the b10-dhcp6 program. Higher numbers equate to more verbose (and detailed) +/// output. + +// Debug levels used to log information during startup and shutdown. +const int DBG_DHCP6_START = DBGLVL_START_SHUT; +const int DBG_DHCP6_SHUT = DBGLVL_START_SHUT; + +// Debug level used to log setting information (such as configuration changes). +const int DBG_DHCP6_COMMAND = DBGLVL_COMMAND; + +// Trace basic operations within the code. +const int DBG_DHCP6_BASIC = DBGLVL_TRACE_BASIC; + +// Trace detailed operations, including errors raised when processing invalid +// packets. (These are not logged at severities of WARN or higher for fear +// that a set of deliberately invalid packets set to the server could overwhelm +// the logging.) +const int DBG_DHCP6_DETAIL = DBGLVL_TRACE_DETAIL; + +// This level is used to log the contents of packets received and sent. +const int DBG_DHCP6_DETAIL_DATA = DBGLVL_TRACE_DETAIL_DATA; + +/// Define the logger for the "dhcp6" module part of b10-dhcp6. We could define +/// a logger in each file, but we would want to define a common name to avoid +/// spelling mistakes, so it is just one small step from there to define a +/// module-common logger. +extern isc::log::Logger dhcp6_logger; + +} // namespace dhcp6 +} // namespace isc + +#endif // __DHCP6_LOG__H diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 9b43f5374f..7c21941d4d 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -14,23 +14,25 @@ #include #include -#include -#include -#include -#include -#include -#include -#include + #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -using namespace std; using namespace isc; -using namespace isc::dhcp; using namespace isc::asiolink; +using namespace isc::dhcp; using namespace isc::util; +using namespace std; const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd"; const uint32_t HARDCODED_T1 = 1500; // in seconds @@ -40,14 +42,14 @@ const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1"; Dhcpv6Srv::Dhcpv6Srv(uint16_t port) { - cout << "Initialization: opening sockets on port " << port << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port); - // first call to instance() will create IfaceMgr (it's a singleton) + // First call to instance() will create IfaceMgr (it's a singleton) // it may throw something if things go wrong try { if (IfaceMgr::instance().countIfaces() == 0) { - cout << "Failed to detect any network interfaces. Aborting." << endl; + LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES); shutdown_ = true; return; } @@ -59,7 +61,7 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) { /// @todo: instantiate LeaseMgr here once it is imlpemented. } catch (const std::exception &e) { - cerr << "Error during DHCPv4 server startup: " << e.what() << endl; + LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what()); shutdown_ = true; return; } @@ -68,13 +70,11 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) { } Dhcpv6Srv::~Dhcpv6Srv() { - cout << "DHCPv6 Srv shutdown." << endl; - IfaceMgr::instance().closeSockets(); } void Dhcpv6Srv::shutdown() { - cout << "b10-dhcp6: DHCPv6 server shutdown." << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_SHUTDOWN_REQUEST); shutdown_ = true; } @@ -89,42 +89,58 @@ bool Dhcpv6Srv::run() { if (query) { if (!query->unpack()) { - cout << "Failed to parse incoming packet" << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, + DHCP6_PACKET_PARSE_FAIL); continue; } + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED) + .arg(serverReceivedPacketName(query->getType())) + .arg(query->getType()); + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA) + .arg(query->getType()) + .arg(query->getBuffer().getLength()) + .arg(query->toText()); + switch (query->getType()) { case DHCPV6_SOLICIT: rsp = processSolicit(query); break; + case DHCPV6_REQUEST: rsp = processRequest(query); break; + case DHCPV6_RENEW: rsp = processRenew(query); break; + case DHCPV6_REBIND: rsp = processRebind(query); break; + case DHCPV6_CONFIRM: rsp = processConfirm(query); break; + case DHCPV6_RELEASE: rsp = processRelease(query); break; + case DHCPV6_DECLINE: rsp = processDecline(query); break; + case DHCPV6_INFORMATION_REQUEST: rsp = processInfRequest(query); break; + default: - cout << "Unknown pkt type received:" - << query->getType() << endl; + // Only action is to output a message if debug is enabled, + // and that will be covered by the debug statement before + // the "switch" statement. + ; } - cout << "Received " << query->getBuffer().getLength() << " bytes packet type=" - << query->getType() << endl; - cout << query->toText(); if (rsp) { rsp->setRemoteAddr(query->getRemoteAddr()); rsp->setLocalAddr(query->getLocalAddr()); @@ -132,14 +148,16 @@ bool Dhcpv6Srv::run() { rsp->setLocalPort(DHCP6_SERVER_PORT); rsp->setIndex(query->getIndex()); rsp->setIface(query->getIface()); - cout << "Replying with:" << rsp->getType() << endl; - cout << rsp->toText(); - cout << "----" << endl; - if (!rsp->pack()) { - cout << "Failed to assemble response packet." << endl; - continue; + + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, + DHCP6_RESPONSE_DATA) + .arg(rsp->getType()).arg(rsp->toText()); + + if (rsp->pack()) { + IfaceMgr::instance().send(rsp); + } else { + LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL); } - IfaceMgr::instance().send(rsp); } } @@ -350,3 +368,46 @@ Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) { Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid())); return reply; } + +const char* +Dhcpv6Srv::serverReceivedPacketName(uint8_t type) { + static const char* CONFIRM = "CONFIRM"; + static const char* DECLINE = "DECLINE"; + static const char* INFORMATION_REQUEST = "INFORMATION_REQUEST"; + static const char* REBIND = "REBIND"; + static const char* RELEASE = "RELEASE"; + static const char* RENEW = "RENEW"; + static const char* REQUEST = "REQUEST"; + static const char* SOLICIT = "SOLICIT"; + static const char* UNKNOWN = "UNKNOWN"; + + switch (type) { + case DHCPV6_CONFIRM: + return (CONFIRM); + + case DHCPV6_DECLINE: + return (DECLINE); + + case DHCPV6_INFORMATION_REQUEST: + return (INFORMATION_REQUEST); + + case DHCPV6_REBIND: + return (REBIND); + + case DHCPV6_RELEASE: + return (RELEASE); + + case DHCPV6_RENEW: + return (RENEW); + + case DHCPV6_REQUEST: + return (REQUEST); + + case DHCPV6_SOLICIT: + return (SOLICIT); + + default: + ; + } + return (UNKNOWN); +} diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index 9d1bf19497..3ef57fdb19 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -69,6 +69,24 @@ public: /// @brief Instructs the server to shut down. void shutdown(); + + /// @brief Return textual type of packet received by server + /// + /// Returns the name of valid packet received by the server (e.g. DISCOVER). + /// If the packet is unknown - or if it is a valid DHCP packet but not one + /// expected to be received by the server (such as an OFFER), the string + /// "UNKNOWN" is returned. This methos is used in debug messages. + /// + /// As the operation of the method does not depend on any server state, it + /// is declared static. + /// + /// @param type DHCPv4 packet type + /// + /// @return Pointer to "const" string containing the packet name. + /// Note that this string is statically allocated and MUST NOT + /// be freed by the caller. + static const char* serverReceivedPacketName(uint8_t type); + protected: /// @brief Processes incoming SOLICIT and returns response. /// diff --git a/src/bin/dhcp6/main.cc b/src/bin/dhcp6/main.cc index aebee90699..8eaf60cb97 100644 --- a/src/bin/dhcp6/main.cc +++ b/src/bin/dhcp6/main.cc @@ -14,13 +14,15 @@ #include #include -#include -#include -#include + #include -using namespace std; +#include +#include +#include + using namespace isc::dhcp; +using namespace std; /// This file contains entry point (main() function) for standard DHCPv6 server /// component for BIND10 framework. It parses command-line arguments and @@ -37,11 +39,10 @@ const char* const DHCP6_NAME = "b10-dhcp6"; void usage() { - cerr << "Usage: b10-dhcp6 [-v]" - << endl; - cerr << "\t-v: verbose output" << endl; - cerr << "\t-s: stand-alone mode (don't connect to BIND10)" << endl; - cerr << "\t-p number: specify non-standard port number 1-65535 " + cerr << "Usage: " << DHCP6_NAME << " [-v] [-s] [-p number]" << endl; + cerr << " -v: verbose output" << endl; + cerr << " -s: stand-alone mode (don't connect to BIND10)" << endl; + cerr << " -p number: specify non-standard port number 1-65535 " << "(useful for testing only)" << endl; exit(EXIT_FAILURE); } @@ -52,18 +53,19 @@ main(int argc, char* argv[]) { int ch; int port_number = DHCP6_SERVER_PORT; // The default. Any other values are // useful for testing only. + bool stand_alone = false; // Should be connect to BIND10 msgq? bool verbose_mode = false; // Should server be verbose? - bool stand_alone = false; // should be connect to BIND10 msgq? while ((ch = getopt(argc, argv, "vsp:")) != -1) { switch (ch) { case 'v': verbose_mode = true; - isc::log::denabled = true; break; + case 's': stand_alone = true; break; + case 'p': try { port_number = boost::lexical_cast(optarg); @@ -78,51 +80,45 @@ main(int argc, char* argv[]) { usage(); } break; - case ':': + default: usage(); } } + // Check for extraneous parameters. + if (argc > optind) { + usage(); + } + // Initialize logging. If verbose, we'll use maximum verbosity. isc::log::initLogger(DHCP6_NAME, (verbose_mode ? isc::log::DEBUG : isc::log::INFO), isc::log::MAX_DEBUG_LEVEL, NULL); - - cout << "b10-dhcp6: My pid=" << getpid() << ", binding to port " - << port_number << ", verbose " << (verbose_mode?"yes":"no") - << ", stand-alone=" << (stand_alone?"yes":"no") << endl; - - if (argc - optind > 0) { - usage(); - } + LOG_INFO(dhcp6_logger, DHCP6_STARTING); + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_START_INFO) + .arg(getpid()).arg(port_number).arg(verbose_mode ? "yes" : "no") + .arg(stand_alone ? "yes" : "no" ); int ret = EXIT_SUCCESS; - try { - - cout << "b10-dhcp6: Initiating DHCPv6 server operation." << endl; - - /// @todo: pass verbose to the actual server once logging is implemented ControlledDhcpv6Srv server(port_number); - if (!stand_alone) { try { server.establishSession(); } catch (const std::exception& ex) { - cerr << "Failed to establish BIND10 session. " - "Running in stand-alone mode:" << ex.what() << endl; + LOG_ERROR(dhcp6_logger, DHCP6_SESSION_FAIL).arg(ex.what()); // Let's continue. It is useful to have the ability to run // DHCP server in stand-alone mode, e.g. for testing } } else { - cout << "Skipping connection to the BIND10 msgq." << endl; + LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_STANDALONE); } - server.run(); + LOG_INFO(dhcp6_logger, DHCP6_SHUTDOWN); } catch (const std::exception& ex) { - cerr << "[b10-dhcp6] Server failed: " << ex.what() << endl; + LOG_FATAL(dhcp6_logger, DHCP6_SERVER_FAILED).arg(ex.what()); ret = EXIT_FAILURE; } diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index 66dc252830..97d2d08572 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/src/bin/dhcp6/tests/Makefile.am @@ -42,10 +42,13 @@ if HAVE_GTEST TESTS += dhcp6_unittests -dhcp6_unittests_SOURCES = ../dhcp6_srv.h ../dhcp6_srv.cc ../ctrl_dhcp6_srv.cc -dhcp6_unittests_SOURCES += dhcp6_unittests.cc +dhcp6_unittests_SOURCES = dhcp6_unittests.cc dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc +dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc +dhcp6_unittests_SOURCES += ../dhcp6_log.h ../dhcp6_log.cc +dhcp6_unittests_SOURCES += ../dhcp6_messages.h ../dhcp6_messages.cc +dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc if USE_CLANGPP # Disable unused parameter warning caused by some of the diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 5e98e18ed2..0e494e972b 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -223,4 +223,49 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) { // more checks to be implemented } +TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) { + // Check all possible packet types + for (int itype = 0; itype < 256; ++itype) { + uint8_t type = itype; + + switch (type) { + case DHCPV6_CONFIRM: + EXPECT_STREQ("CONFIRM", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_DECLINE: + EXPECT_STREQ("DECLINE", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_INFORMATION_REQUEST: + EXPECT_STREQ("INFORMATION_REQUEST", + Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_REBIND: + EXPECT_STREQ("REBIND", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_RELEASE: + EXPECT_STREQ("RELEASE", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_RENEW: + EXPECT_STREQ("RENEW", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_REQUEST: + EXPECT_STREQ("REQUEST", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + case DHCPV6_SOLICIT: + EXPECT_STREQ("SOLICIT", Dhcpv6Srv::serverReceivedPacketName(type)); + break; + + default: + EXPECT_STREQ("UNKNOWN", Dhcpv6Srv::serverReceivedPacketName(type)); + } + } } + +} // oF ANONYMOUS NAMESPACE diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py index 399c370742..0887bbf2a0 100644 --- a/src/bin/dhcp6/tests/dhcp6_test.py +++ b/src/bin/dhcp6/tests/dhcp6_test.py @@ -27,16 +27,23 @@ import fcntl class TestDhcpv6Daemon(unittest.TestCase): def setUp(self): - # don't redirect stdout/stderr here as we want to print out things + # Don't redirect stdout/stderr here as we want to print out things # during the test - pass + # + # However, we do want to set the logging lock directory to somewhere + # to which we can write - use the current working directory. We then + # set the appropriate environment variable. + lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD" + lockdir = os.getenv(lockdir_envvar) + if lockdir is None: + os.putenv(lockdir_envvar, os.getcwd()) def tearDown(self): pass def runCommand(self, params, wait=1): """ - This method runs a command and returns a touple: (returncode, stdout, stderr) + This method runs a command and returns a tuple: (returncode, stdout, stderr) """ ## @todo: Convert this into generic method and reuse it in dhcp4 and dhcp6 @@ -79,9 +86,9 @@ class TestDhcpv6Daemon(unittest.TestCase): fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) # There's potential problem if b10-dhcp4 prints out more - # than 4k of text + # than 16k of text try: - output = os.read(self.stdout_pipes[0], 4096) + output = os.read(self.stdout_pipes[0], 16384) except OSError: print("No data available from stdout") output = "" @@ -91,7 +98,7 @@ class TestDhcpv6Daemon(unittest.TestCase): output = "" try: - error = os.read(self.stderr_pipes[0], 4096) + error = os.read(self.stderr_pipes[0], 16384) except OSError: print("No data available on stderr") error = "" @@ -130,8 +137,8 @@ class TestDhcpv6Daemon(unittest.TestCase): print("Note: Purpose of some of the tests is to check if DHCPv6 server can be started,") print(" not that is can bind sockets correctly. Please ignore binding errors.") (returncode, output, error) = self.runCommand(["../b10-dhcp6", "-v"]) - - self.assertEqual( str(output).count("b10-dhcp6: Initiating DHCPv6 server operation."), 1) + output_text = str(output) + str(error) + self.assertEqual(output_text.count("DHCP6_STARTING"), 1) def test_portnumber_0(self): print("Check that specifying port number 0 is not allowed.") @@ -180,27 +187,19 @@ class TestDhcpv6Daemon(unittest.TestCase): def test_portnumber_nonroot(self): print("Check that specifying unprivileged port number will work.") - (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-s', '-p', '10547']) - - # When invalid port number is specified, return code must not be success - # TODO: Temporarily commented out as socket binding on systems that do not have - # interface detection implemented currently fails. - # self.assertTrue(returncode == 0) - - self.assertEqual( str(output).count("opening sockets on port 10547"), 1) + # Check that there is a message about running with an unprivileged port + (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-v', '-s', '-p', '10547']) + output_text = str(output) + str(error) + self.assertEqual(output_text.count("DHCP6_OPEN_SOCKET opening sockets on port 10547"), 1) def test_skip_msgq(self): print("Check that connection to BIND10 msgq can be disabled.") - (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-s', '-p', '10547']) - - # When invalid port number is specified, return code must not be success - # TODO: Temporarily commented out as socket binding on systems that do not have - # interface detection implemented currently fails. - # self.assertTrue(returncode == 0) - - self.assertEqual( str(output).count("Skipping connection to the BIND10 msgq."), 1) - + # Check that the system outputs a message on one of its streams about running + # standalone. + (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-v', '-s', '-p', '10547']) + output_text = str(output) + str(error) + self.assertEqual(output_text.count("DHCP6_STANDALONE"), 1) if __name__ == '__main__': unittest.main() From db4da6a255d11e40baf72bcef298312d63c8749c Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Thu, 6 Sep 2012 19:35:27 +0200 Subject: [PATCH 114/148] [2143] Minor changes after review. --- tests/tools/dhcp-ubench/dhcp-perf-guide.html | 55 +++++++----- tests/tools/dhcp-ubench/dhcp-perf-guide.xml | 88 +++++++++++--------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.html b/tests/tools/dhcp-ubench/dhcp-perf-guide.html index 08475d323b..40a07581dc 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.html +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.html @@ -1,11 +1,11 @@ -DHCP Performance Guide

    DHCP Performance Guide

    Tomasz Mrugalski

    This is a companion document for BIND 10 version - 20120405.

    Abstract

    BIND 10 is a framework that features Domain Name System +DHCP Performance Guide

    DHCP Performance Guide

    Tomasz Mrugalski

    This is a companion document for BIND 10 version + 20120712.

    Abstract

    BIND 10 is a framework that features Domain Name System (DNS) and Dynamic Host Configuration Protocol (DHCP) software with development managed by Internet Systems Consortium (ISC). This document describes various aspects of DHCP performance, measurements and tuning. It covers BIND 10 DHCP (codename Kea), existing ISC DHCP4 software, perfdhcp (a DHCP performance - measurement tool) and other related topics.


    Preface

    Table of Contents

    1. Acknowledgements

    1. Acknowledgements

    ISC would like to acknowledge generous support for + measurement tool) and other related topics.


    Preface

    Table of Contents

    1. Acknowledgements

    1. Acknowledgements

    ISC would like to acknowledge generous support for BIND 10 development of DHCPv4 and DHCPv6 components provided by Comcast.

    Chapter 1. Introduction

    This document is in the early stages of development. It is @@ -14,9 +14,9 @@ tools, and the pros an cons of various optimization techniques.

    Chapter 2. ISC DHCP 4.x

    TODO: Write something about ISC DHCP4 here. -

    Chapter 3. Kea

    -

    3.1. Backend performance evaluation

    +

    3.1. Backend performance evaluation

    Kea will support several different database backends, using both popular databases (like MySQL or SQLite) and custom-developed solutions (such as an in-memory database). @@ -113,7 +113,13 @@ Possible command-line parameters: -c yes|no - should compiled statements be used (MySQL only)

    -

    3.2.1. MySQL tweaks

    One parameter that has huge impact on performance is the choice of backend engine. +

    Synchronous operation requires database backend to + physically store changes to disk before proceeding. This + property ensures that no data is lost in case of the server + failure. Unfortunately, it slows operation + considerably. Asynchronous mode allows database to write data at + a later time (usually controlled by the database engine on OS + disk buffering mechanism).

    3.2.1. MySQL tweaks

    One parameter that has huge impact on performance is the choice of backend engine. You can get a list of engines of your MySQL implementation by using

    > show engines;

    @@ -154,13 +160,16 @@ Possible command-line parameters: http://www.sqlite.org/pragma.html#pragma_journal_mode for detailed explanantion.

    sqlite_bench supports precompiled statements. Please use '-c no|yes' to define which should be used: basic SQL query (no) or - precompiled statement (yes).

    3.4. memfile-ubench

    The memfile backend is a custom backend that - somewhat mimics operation of ISC DHCP4. It implements in-memory - storage using standard C++ and boost mechanisms (std::map and - boost::shared_ptr<>). All database changes are also - written to a lease file, which is strictly write-only. This - approach takes advantage of the fact that simple append is faster - than edition with potential whole file relocation.

    3.4.1. memfile tweaks

    To modify default memfile_ubench parameters, command line + precompiled statement (yes).

    3.4. memfile-ubench

    The memfile backend is a + custom backend that somewhat mimics operation of ISC DHCP4. It + implements in-memory storage using standard C++ and boost + mechanisms (std::map and boost::shared_ptr<>). All + database changes are also written to a lease file, which is + strictly write-only. This approach takes advantage of the fact + that file append operation is faster than modifications introduced + in the middle of the file (as it often requires moving all data + after modified point, effectively requiring writing large parts of + the whole file, not just changed fragment).

    3.4.1. memfile tweaks

    To modify default memfile_ubench parameters, command line switches can be used. Currently supported switches are (default values specified in brackets):

    1. -f filename - name of the database file ("dhcpd.leases")

    2. -n num - number of iterations (100)

    3. -s yes|no - should the operations be performend in a synchronous (yes) @@ -168,7 +177,7 @@ Possible command-line parameters:

      memfile can run in asynchronous or synchronous mode. This mode can be controlled by using sync parameter. It uses fflush() and fsync() in synchronous mode to make sure that - data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, + data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    @@ -183,13 +192,13 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
           asynchronous. As those modes offer radically different
           performances, synchronous mode was conducted for one
           thousand repetitions and asynchronous mode was conducted for
    -      one hundred thousand repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00031.603978 0.11661227.96419127.69520921.844998
    SQLite1,00061.421356 0.03328359.47663856.03415044.241357
    memfile1,00038.223757 0.00081738.04115338.01729328.570755

    The following parameters were measured for asynchronous mode. + one hundred thousand repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00031.604 0.11727.96427.69521.845
    SQLite1,00061.421 0.03359.47756.03444.241
    memfile1,00038.224 0.00138.04138.01728.571

    The following parameters were measured for asynchronous mode. MySQL and SQLite were run with one hundred thousand repetitions. Memfile - was run for one million repetitions due to its much higher performance.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,00010.58484210.38640210.062384 8.890197 9.980956
    SQLite100,000 3.710356 3.159129 2.865354 2.439406 3.043561
    memfile1,000,000 1.299642 0.039330 1.307112 1.277641 0.980931

    The presented performance results can be converted into operations per second metrics. + was run for one million repetitions due to its much higher performance.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,00010.58510.38610.062 8.890 9.981
    SQLite100,000 3.710 3.159 2.865 2.439 3.044
    memfile1,000,000 1.300 0.039 1.307 1.278 0.981

    The presented performance results can be converted into operations per second metrics. It should be noted that due to large differences between various operations (sometimes over three orders of magnitude), it is difficult to create a simple, readable chart with - that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Basic performance measurements

    Graphical representation of the basic performance results - presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, + that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Basic performance measurements

    Graphical representation of the basic performance results + presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    @@ -204,13 +213,13 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
           asynchronous. As those modes offer radically different
           performances, synchronous mode was conducted for one
           thousand repetitions and asynchronous mode was conducted for
    -      one hundred thousand repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00027.887 0.10628.22327.69620.978
    SQLite1,00061.299 0.01559.64861.09845.626
    memfile1,00039.564 0.00072439.54339.32629.608

    The following parameters were measured for asynchronous mode. + one hundred thousand repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00027.887 0.10628.22327.69620.978
    SQLite1,00061.299 0.01559.64861.09845.626
    memfile1,00039.564 0.00139.54339.32629.608

    The following parameters were measured for asynchronous mode. MySQL and SQLite were run with one hundred thousand repetitions. Memfile - was run for one million repetitions due to its much higher performance.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,0008.5079.6987.7858.3268.579
    SQLite100,000 1.562 0.949 1.513 1.502 1.382
    memfile1,000,0001.3020.0381.3061.2630.977

    The presented performance results can be converted into operations per second metrics. + was run for one million repetitions due to its much higher performance.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,0008.5079.6987.7858.3268.579
    SQLite100,000 1.562 0.949 1.513 1.502 1.382
    memfile1,000,0001.3020.0381.3061.2630.977

    The presented performance results can be converted into operations per second metrics. It should be noted that due to large differences between various operations (sometime over three orders of magnitude), it is difficult to create a simple, readable chart with - the data.

    Table 3.6. Estimated optimized performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)11754.8410311.3412845.3512010.2411730.44
    SQLite (async)64005.90105391.2966075.5166566.4375509.78
    memfile (async)76832.162636018.5676542.5079188.81717145.51
    MySQL (sync)35.869461.1035.4336.112392.12
    SQLite (sync)16.3167036.1116.7616.3716771.39
    memfile (sync)25.283460207.6125.2925.43865070.90

    Optimized performance measurements

    Graphical representation of the optimized performance - results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    + the data.

    Table 3.6. Estimated optimized performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)11754.8410311.3412845.3512010.2411730.44
    SQLite (async)64005.90105391.2966075.5166566.4375509.78
    memfile (async)76832.162636018.5676542.5079188.81717145.51
    MySQL (sync)35.869461.1035.4336.112392.12
    SQLite (sync)16.3167036.1116.7616.3716771.39
    memfile (sync)25.283460207.6125.2925.43865070.90

    Optimized performance measurements

    Graphical representation of the optimized performance + results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    Improvements gained by introducing support for precompiled statements in MySQL is somewhat disappointing - between 6 and 29%. On the other hand, the improvement in SQLite is @@ -258,7 +267,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 message. The provided results should be considered as only rough estimates. They can also be used for relative comparisons between backends. -

    3.8. Possible further optimizations

    +

    3.8. Possible further optimizations

    For basic measurements the code was compiled with -g -O0 flags. For optimized measurements the benchmarking code was compiled with -Ofast (optimize for speed). In both cases, the diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml index f149c44ea6..6e3846731d 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml @@ -237,6 +237,14 @@ Possible command-line parameters: + Synchronous operation requires database backend to + physically store changes to disk before proceeding. This + property ensures that no data is lost in case of the server + failure. Unfortunately, it slows operation + considerably. Asynchronous mode allows database to write data at + a later time (usually controlled by the database engine on OS + disk buffering mechanism). +

    MySQL tweaks @@ -315,14 +323,16 @@ Possible command-line parameters:
    - memfile-ubench - The memfile backend is a custom backend that - somewhat mimics operation of ISC DHCP4. It implements in-memory - storage using standard C++ and boost mechanisms (std::map and - boost::shared_ptr<>). All database changes are also - written to a lease file, which is strictly write-only. This - approach takes advantage of the fact that simple append is faster - than edition with potential whole file relocation. + memfile-ubench The memfile backend is a + custom backend that somewhat mimics operation of ISC DHCP4. It + implements in-memory storage using standard C++ and boost + mechanisms (std::map and boost::shared_ptr<>). All + database changes are also written to a lease file, which is + strictly write-only. This approach takes advantage of the fact + that file append operation is faster than modifications introduced + in the middle of the file (as it often requires moving all data + after modified point, effectively requiring writing large parts of + the whole file, not just changed fragment).
    memfile tweaks @@ -393,31 +403,31 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 MySQL 1,000 - 31.603978 - 0.116612 - 27.964191 - 27.695209 - 21.844998 + 31.604 + 0.117 + 27.964 + 27.695 + 21.845 SQLite 1,000 - 61.421356 - 0.033283 - 59.476638 - 56.034150 - 44.241357 + 61.421 + 0.033 + 59.477 + 56.034 + 44.241 memfile 1,000 - 38.223757 - 0.000817 - 38.041153 - 38.017293 - 28.570755 + 38.224 + 0.001 + 38.041 + 38.017 + 28.571 @@ -453,31 +463,31 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 MySQL 100,000 - 10.584842 - 10.386402 - 10.062384 - 8.890197 - 9.980956 + 10.585 + 10.386 + 10.062 + 8.890 + 9.981 SQLite 100,000 - 3.710356 - 3.159129 - 2.865354 - 2.439406 - 3.043561 + 3.710 + 3.159 + 2.865 + 2.439 + 3.044 memfile 1,000,000 - 1.299642 - 0.039330 - 1.307112 - 1.277641 - 0.980931 + 1.300 + 0.039 + 1.307 + 1.278 + 0.981 @@ -651,7 +661,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile 1,000 39.564 - 0.000724 + 0.001 39.543 39.326 29.608 From 31c4fcd5cd9f77e112090250d2571f975dba7ef4 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 7 Sep 2012 07:12:23 -0500 Subject: [PATCH 115/148] [master] Allow for one more second in NXDOMAIN TTL checks We have had 34 random off-by-one failures on real and virtual machines. Previously it allowed a two second range (it slept for 2 seconds). Now allow a three second range. Discussed on jabber. --- src/lib/cache/tests/negative_cache_unittest.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/cache/tests/negative_cache_unittest.cc b/src/lib/cache/tests/negative_cache_unittest.cc index 4935e4a6af..78537631a3 100644 --- a/src/lib/cache/tests/negative_cache_unittest.cc +++ b/src/lib/cache/tests/negative_cache_unittest.cc @@ -98,8 +98,9 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){ rrset_ptr = *iter; // The TTL should equal to the TTL of negative response SOA record + // Allow for three second range. const RRTTL& nxdomain_ttl2 = rrset_ptr->getTTL(); - EXPECT_GE(nxdomain_ttl2.getValue(), 86397); + EXPECT_GE(nxdomain_ttl2.getValue(), 86396); EXPECT_LE(nxdomain_ttl2.getValue(), 86398); // No RRset in ANSWER section EXPECT_TRUE(msg_nxdomain2.getRRCount(Message::SECTION_ANSWER) == 0); @@ -120,7 +121,8 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){ rrset_ptr = *iter; const RRTTL& soa_ttl2 = rrset_ptr->getTTL(); // The TTL should equal to the TTL of SOA record in answer section - EXPECT_GE(soa_ttl2.getValue(), 172797); + // Allow for three second range. + EXPECT_GE(soa_ttl2.getValue(), 172796); EXPECT_LE(soa_ttl2.getValue(), 172798); } From e1631485dc9fe6cbe061b4a4a3f5a5b6c6cd8080 Mon Sep 17 00:00:00 2001 From: "Jeremy C. Reed" Date: Fri, 7 Sep 2012 07:33:23 -0500 Subject: [PATCH 116/148] [master] comment sentence about cache-enable hiding zones It doesn't happen currently. See ticket http://bind10.isc.org/ticket/2240 --- doc/guide/bind10-guide.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml index 283119800f..a95b0f540e 100644 --- a/doc/guide/bind10-guide.xml +++ b/doc/guide/bind10-guide.xml @@ -1765,10 +1765,14 @@ can use various data source backends. answering up. The first option is cache-enable, a boolean value turning the cache on and off (off is the default). The second one, cache-zones, is a list of zone - origins to load into in-memory. Once the cache is enabled, + origins to load into in-memory. + +
    From c3689c6a256a1a77993ec743be8bd76506b72bd2 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Fri, 7 Sep 2012 15:03:39 +0200 Subject: [PATCH 117/148] [master] cleanup version-check sqt statements This should fix the valgrind error report, verified on jabber --- src/lib/datasrc/sqlite3_accessor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc index 457d578c4b..24d7b3f72a 100644 --- a/src/lib/datasrc/sqlite3_accessor.cc +++ b/src/lib/datasrc/sqlite3_accessor.cc @@ -394,16 +394,19 @@ int checkSchemaVersionElement(sqlite3* db, const char* const query) { if (rc == SQLITE_ERROR) { // this is the error that is returned when the table does not // exist + sqlite3_finalize(prepared); return (-1); } else if (rc == SQLITE_OK) { break; } else if (rc != SQLITE_BUSY || i == 50) { + sqlite3_finalize(prepared); isc_throw(SQLite3Error, "Unable to prepare version query: " << rc << " " << sqlite3_errmsg(db)); } doSleep(); } if (sqlite3_step(prepared) != SQLITE_ROW) { + sqlite3_finalize(prepared); isc_throw(SQLite3Error, "Unable to query version: " << sqlite3_errmsg(db)); } From ed1a5d91d8ca0826a6c6370abfa511c052b60c24 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Fri, 7 Sep 2012 17:20:28 +0200 Subject: [PATCH 118/148] [2151] add well-known static wildcard labelsequence --- src/lib/dns/labelsequence.h | 15 +++++++++++++++ src/lib/dns/tests/labelsequence_unittest.cc | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h index 545ce12133..b9105506c1 100644 --- a/src/lib/dns/labelsequence.h +++ b/src/lib/dns/labelsequence.h @@ -53,6 +53,14 @@ public: static const size_t MAX_SERIALIZED_LENGTH = Name::MAX_WIRE + Name::MAX_LABELS + 1; + /// + /// \name Well-known LabelSequence constants + /// + //@{ + /// Wildcard label ("*") + static const LabelSequence& WILDCARD_LABEL(); + //@} + /// \brief Constructs a LabelSequence for the given name /// /// \note The associated Name MUST remain in scope during the lifetime @@ -410,6 +418,13 @@ private: std::ostream& operator<<(std::ostream& os, const LabelSequence& label_sequence); +inline const LabelSequence& +LabelSequence::WILDCARD_LABEL() { + static const uint8_t wildcard_buf[4] = { 0x01, 0x00, 0x01, '*' }; + static const LabelSequence wild_ls(wildcard_buf); + return (wild_ls); +} + } // end namespace dns } // end namespace isc diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc index 28f624aabd..06092c008e 100644 --- a/src/lib/dns/tests/labelsequence_unittest.cc +++ b/src/lib/dns/tests/labelsequence_unittest.cc @@ -1174,4 +1174,10 @@ TEST_F(ExtendableLabelSequenceTest, extendBadData) { check_equal(full_ls2, els); } +// Check the static fixed 'wildcard' LabelSequence +TEST(WildCardLabelSequence, wildcard) { + ASSERT_FALSE(LabelSequence::WILDCARD_LABEL().isAbsolute()); + ASSERT_EQ("*", LabelSequence::WILDCARD_LABEL().toText()); +} + } From 7f11d6a78b0204046dacc1a8a3c853749b62162c Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Sat, 8 Sep 2012 12:07:03 +0900 Subject: [PATCH 119/148] [master] editorial cleanup: combine two short lines I just happen to notice it, and since it's very trivial I'm making the change directly. --- src/bin/auth/query.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc index 6ccd4d2538..69278d4e6d 100644 --- a/src/bin/auth/query.cc +++ b/src/bin/auth/query.cc @@ -562,8 +562,7 @@ Query::reset() { bool Query::processDSAtChild() { - const ClientList::FindResult zresult = - client_list_->find(*qname_, true); + const ClientList::FindResult zresult = client_list_->find(*qname_, true); if (zresult.dsrc_client_ == NULL) { return (false); From 10cf1a64da6a0d8851984e6ca0c6c7baa6769c20 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Mon, 10 Sep 2012 15:22:30 +0200 Subject: [PATCH 120/148] [1959] Added couple @todos for postponed things during review, part 1. --- src/lib/dhcp/iface_mgr.cc | 12 +++++++++--- src/lib/dhcp/iface_mgr.h | 2 ++ src/lib/dhcp/option.h | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 54db434d8f..9c03794c2d 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -498,11 +498,15 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) { asio::error_code err_code; // If remote address is broadcast address we have to // allow this on the socket. - if (remote_addr.getAddress().is_v4() && + if (remote_addr.getAddress().is_v4() && (remote_addr == IOAddress("255.255.255.255"))) { // Socket has to be open prior to setting the broadcast // option. Otherwise set_option will complain about // bad file descriptor. + + // @todo: We don't specify interface in any way here. 255.255.255.255 + // We can very easily end up with a socket working on a different + // interface. sock.open(asio::ip::udp::v4(), err_code); if (err_code) { isc_throw(Unexpected, "failed to open UDPv4 socket"); @@ -580,8 +584,10 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) { struct sockaddr_in6 addr6; memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; - addr6.sin6_port = htons(port); if (addr.toText() != "::1") - addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str()); + addr6.sin6_port = htons(port); + if (addr.toText() != "::1") { + addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str()); + } memcpy(&addr6.sin6_addr, addr.getAddress().to_v6().to_bytes().data(), diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index 178d24a9ec..cacd720318 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -72,8 +72,10 @@ public: }; /// type that holds a list of socket informations + /// @todo: Add SocketCollectionConstIter type typedef std::list SocketCollection; + /// @brief represents a single network interface /// /// Iface structure represents network interface with all useful diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h index 9589c37ab9..080a869996 100644 --- a/src/lib/dhcp/option.h +++ b/src/lib/dhcp/option.h @@ -63,6 +63,9 @@ public: /// @param type option type /// @param buf pointer to a buffer /// + /// @todo Passing a separate buffer for each option means that a copy + /// was done. We can avoid it by passing 2 iterators. + /// /// @return a pointer to a created option object typedef OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer& buf); From b5aa1dadff2c0e7c9fce8fab0aa6dee28071e29b Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Mon, 10 Sep 2012 20:43:51 +0200 Subject: [PATCH 121/148] [1959] Implemented suggestions from code review. --- tests/tools/perfdhcp/command_options.cc | 3 +- tests/tools/perfdhcp/pkt_transform.h | 2 ++ tests/tools/perfdhcp/test_control.cc | 36 +++++++++++-------- tests/tools/perfdhcp/test_control.h | 34 +++++++++++------- .../perfdhcp/tests/test_control_unittest.cc | 12 +++---- 5 files changed, 54 insertions(+), 33 deletions(-) diff --git a/tests/tools/perfdhcp/command_options.cc b/tests/tools/perfdhcp/command_options.cc index 8d9f02e763..24e7e790dc 100644 --- a/tests/tools/perfdhcp/command_options.cc +++ b/tests/tools/perfdhcp/command_options.cc @@ -12,6 +12,7 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. +#include #include #include #include @@ -866,7 +867,7 @@ CommandOptions::usage() const { void CommandOptions::version() const { - fprintf(stdout, "version 0.01\n"); + std::cout << "VERSION: " << VERSION << std::endl; } diff --git a/tests/tools/perfdhcp/pkt_transform.h b/tests/tools/perfdhcp/pkt_transform.h index 08563a2720..1f57105720 100644 --- a/tests/tools/perfdhcp/pkt_transform.h +++ b/tests/tools/perfdhcp/pkt_transform.h @@ -114,6 +114,8 @@ public: template static void writeValueAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos, T val) { + // @todo consider replacing the loop with switch statement + // checking sizeof(T). for (int i = 0; i < sizeof(T); ++i) { in_buffer[dest_pos + i] = (val >> 8 * (sizeof(T) - i - 1)) & 0xFF; } diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index ef970a7948..090fb32411 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -299,8 +299,8 @@ TestControl::factoryOptionRequestOption6(Option::Universe, uint16_t, const OptionBuffer&) { const uint8_t buf_array[] = { - D6O_NAME_SERVERS, 0, - D6O_DOMAIN_SEARCH, 0, + 0, D6O_NAME_SERVERS, + 0, D6O_DOMAIN_SEARCH, }; OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array)); return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options))); @@ -731,7 +731,7 @@ TestControl::readPacketTemplate(const std::string& file_name) { } void -TestControl::receivePacket4(const TestControlSocket& socket, +TestControl::processReceivedPacket4(const TestControlSocket& socket, const Pkt4Ptr& pkt4) { if (pkt4->getType() == DHCPOFFER) { Pkt4Ptr discover_pkt4(stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_DO, @@ -742,6 +742,8 @@ TestControl::receivePacket4(const TestControlSocket& socket, if (template_buffers_.size() < 2) { sendRequest4(socket, discover_pkt4, pkt4); } else { + // @todo add defines for packet type index that can be + // used to access template_buffers_. sendRequest4(socket, template_buffers_[1], discover_pkt4, pkt4); } } @@ -751,7 +753,7 @@ TestControl::receivePacket4(const TestControlSocket& socket, } void -TestControl::receivePacket6(const TestControlSocket& socket, +TestControl::processReceivedPacket6(const TestControlSocket& socket, const Pkt6Ptr& pkt6) { uint8_t packet_type = pkt6->getType(); if (packet_type == DHCPV6_ADVERTISE) { @@ -766,6 +768,8 @@ TestControl::receivePacket6(const TestControlSocket& socket, if (template_buffers_.size() < 2) { sendRequest6(socket, pkt6); } else { + // @todo add defines for packet type index that can be + // used to access template_buffers_. sendRequest6(socket, template_buffers_[1], pkt6); } } @@ -790,7 +794,7 @@ TestControl::receivePackets(const TestControlSocket& socket) { stats_mgr4_->incrementCounter("multircvd"); } pkt4->unpack(); - receivePacket4(socket, pkt4); + processReceivedPacket4(socket, pkt4); } } else if (CommandOptions::instance().getIpVersion() == 6) { Pkt6Ptr pkt6 = IfaceMgr::instance().receive6(timeout); @@ -802,7 +806,7 @@ TestControl::receivePackets(const TestControlSocket& socket) { stats_mgr6_->incrementCounter("multircvd"); } if (pkt6->unpack()) { - receivePacket6(socket, pkt6); + processReceivedPacket6(socket, pkt6); } } } @@ -949,8 +953,9 @@ TestControl::run() { } else { // Pick template #0 if Discover is being sent. // For Request it would be #1. - const uint8_t template_idx = 0; - sendDiscover4(socket, template_buffers_[template_idx], + // @todo add defines for packet type index that can be + // used to access template_buffers_. + sendDiscover4(socket, template_buffers_[0], do_preload); } } else if (options.getIpVersion() == 6) { @@ -961,8 +966,9 @@ TestControl::run() { } else { // Pick template #0 if Solicit is being sent. // For Request it would be #1. - const uint8_t template_idx = 0; - sendSolicit6(socket, template_buffers_[template_idx], + // @todo add defines for packet type index that can be + // used to access template_buffers_. + sendSolicit6(socket, template_buffers_[0], do_preload); } } @@ -1000,8 +1006,9 @@ TestControl::run() { if (template_buffers_.size() == 0) { sendDiscover4(socket); } else { - const uint8_t template_idx = 0; - sendDiscover4(socket, template_buffers_[template_idx]); + // @todo add defines for packet type index that can be + // used to access template_buffers_. + sendDiscover4(socket, template_buffers_[0]); } } else { // No template packets means that no -T option was specified. @@ -1009,8 +1016,9 @@ TestControl::run() { if (template_buffers_.size() == 0) { sendSolicit6(socket); } else { - const uint8_t template_idx = 0; - sendSolicit6(socket, template_buffers_[template_idx]); + // @todo add defines for packet type index that can be + // used to access template_buffers_. + sendSolicit6(socket, template_buffers_[0]); } } } diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h index 8e492af133..1b0b83c385 100644 --- a/tests/tools/perfdhcp/test_control.h +++ b/tests/tools/perfdhcp/test_control.h @@ -46,6 +46,12 @@ namespace perfdhcp { /// \ref dhcp::Option::factory with DHCP message type specified as one of /// parameters. Some of the parameters passed to factory function /// may be ignored (e.g. option buffer). +/// Please note that naming convention for factory functions within this +/// class is as follows: +/// - factoryABC4 - factory function for DHCPv4 option, +/// - factoryDEF6 - factory function for DHCPv6 option, +/// - factoryGHI - factory function that can be used to create either +/// DHCPv4 or DHCPv6 option. class TestControl : public boost::noncopyable { public: @@ -449,11 +455,11 @@ protected: /// not initialized. void printStats() const; - /// \brief Receive DHCPv4 packet. + /// \brief Process received DHCPv4 packet. /// - /// Method performs reception of the DHCPv4 packet, updates - /// statistics and responsds to the server if required, e.g. - /// when OFFER packet arrives, this function will initiate + /// Method performs processing of the received DHCPv4 packet, + /// updates statistics and responds to the server if required, + /// e.g. when OFFER packet arrives, this function will initiate /// REQUEST message to the server. /// /// \warning this method does not check if provided socket is @@ -463,14 +469,14 @@ protected: /// \param [in] pkt4 object representing DHCPv4 packet received. /// \throw isc::BadValue if unknown message type received. /// \throw isc::Unexpected if unexpected error occured. - void receivePacket4(const TestControlSocket& socket, - const dhcp::Pkt4Ptr& pkt4); + void processReceivedPacket4(const TestControlSocket& socket, + const dhcp::Pkt4Ptr& pkt4); - /// \brief Receive DHCPv6 packet. + /// \brief Process received DHCPv6 packet. /// - /// Method performs reception of the DHCPv6 packet, updates - /// statistics and responsds to the server if required, e.g. - /// when ADVERTISE packet arrives, this function will initiate + /// Method performs processing of the received DHCPv6 packet, + /// updates statistics and responsds to the server if required, + /// e.g. when ADVERTISE packet arrives, this function will initiate /// REQUEST message to the server. /// /// \warning this method does not check if provided socket is @@ -480,8 +486,8 @@ protected: /// \param [in] pkt6 object representing DHCPv6 packet received. /// \throw isc::BadValue if unknown message type received. /// \throw isc::Unexpected if unexpected error occured. - void receivePacket6(const TestControlSocket& socket, - const dhcp::Pkt6Ptr& pkt6); + void processReceivedPacket6(const TestControlSocket& socket, + const dhcp::Pkt6Ptr& pkt6); /// \brief Receive DHCPv4 or DHCPv6 packets from the server. /// @@ -706,6 +712,8 @@ private: /// \brief Convert binary value to hex string. /// + /// \todo Consider moving this function to src/lib/util. + /// /// \param b byte to convert. /// \return hex string. std::string byte2Hex(const uint8_t b) const; @@ -760,6 +768,8 @@ private: /// \brief Convert vector in hexadecimal string. /// + /// \todo Consider moving this function to src/lib/util. + /// /// \param vec vector to be converted. /// \param separator separator. std::string vector2Hex(const std::vector& vec, diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc index e5dbaf12a2..a4cde00f19 100644 --- a/tests/tools/perfdhcp/tests/test_control_unittest.cc +++ b/tests/tools/perfdhcp/tests/test_control_unittest.cc @@ -81,8 +81,8 @@ public: using TestControl::initPacketTemplates; using TestControl::initializeStatsMgr; using TestControl::openSocket; - using TestControl::receivePacket4; - using TestControl::receivePacket6; + using TestControl::processReceivedPacket4; + using TestControl::processReceivedPacket6; using TestControl::registerOptionFactories; using TestControl::sendDiscover4; using TestControl::sendSolicit6; @@ -418,7 +418,7 @@ public: // packet drops. if (i < receive_num) { boost::shared_ptr offer_pkt4(createOfferPkt4(transid)); - ASSERT_NO_THROW(tc.receivePacket4(sock, offer_pkt4)); + ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer_pkt4)); ++transid; } if (tc.checkExitConditions()) { @@ -483,7 +483,7 @@ public: boost::shared_ptr advertise_pkt6(createAdvertisePkt6(transid)); // Receive ADVERTISE and send REQUEST. - ASSERT_NO_THROW(tc.receivePacket6(sock, advertise_pkt6)); + ASSERT_NO_THROW(tc.processReceivedPacket6(sock, advertise_pkt6)); ++transid; } if (tc.checkExitConditions()) { @@ -770,8 +770,8 @@ TEST_F(TestControlTest, Options6) { OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO)); // Prepare the reference buffer with requested options. const uint8_t requested_options[] = { - D6O_NAME_SERVERS, 0, - D6O_DOMAIN_SEARCH, 0, + 0, D6O_NAME_SERVERS, + 0, D6O_DOMAIN_SEARCH, }; int requested_options_num = sizeof(requested_options) / sizeof(requested_options[0]); From 73291cf04175391585c0222f302150d9bc66a61c Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Tue, 11 Sep 2012 12:19:46 +0200 Subject: [PATCH 122/148] [2151] change name to LabelSequence::WILDCARD --- src/lib/dns/labelsequence.h | 4 ++-- src/lib/dns/tests/labelsequence_unittest.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h index b9105506c1..3f6a03aea7 100644 --- a/src/lib/dns/labelsequence.h +++ b/src/lib/dns/labelsequence.h @@ -58,7 +58,7 @@ public: /// //@{ /// Wildcard label ("*") - static const LabelSequence& WILDCARD_LABEL(); + static const LabelSequence& WILDCARD(); //@} /// \brief Constructs a LabelSequence for the given name @@ -419,7 +419,7 @@ std::ostream& operator<<(std::ostream& os, const LabelSequence& label_sequence); inline const LabelSequence& -LabelSequence::WILDCARD_LABEL() { +LabelSequence::WILDCARD() { static const uint8_t wildcard_buf[4] = { 0x01, 0x00, 0x01, '*' }; static const LabelSequence wild_ls(wildcard_buf); return (wild_ls); diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc index 06092c008e..b7463b2460 100644 --- a/src/lib/dns/tests/labelsequence_unittest.cc +++ b/src/lib/dns/tests/labelsequence_unittest.cc @@ -1176,8 +1176,8 @@ TEST_F(ExtendableLabelSequenceTest, extendBadData) { // Check the static fixed 'wildcard' LabelSequence TEST(WildCardLabelSequence, wildcard) { - ASSERT_FALSE(LabelSequence::WILDCARD_LABEL().isAbsolute()); - ASSERT_EQ("*", LabelSequence::WILDCARD_LABEL().toText()); + ASSERT_FALSE(LabelSequence::WILDCARD().isAbsolute()); + ASSERT_EQ("*", LabelSequence::WILDCARD().toText()); } } From 0ed7d2f838ec4bf431ea8a960a5c44e9c0951481 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 11 Sep 2012 14:16:40 +0200 Subject: [PATCH 123/148] [2143] Minor corrections in DHCP Performance Guide after review. --- tests/tools/dhcp-ubench/dhcp-perf-guide.html | 89 ++++++++-------- tests/tools/dhcp-ubench/dhcp-perf-guide.xml | 103 +++++++++++-------- 2 files changed, 100 insertions(+), 92 deletions(-) diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.html b/tests/tools/dhcp-ubench/dhcp-perf-guide.html index 40a07581dc..df2308341f 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.html +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.html @@ -1,11 +1,11 @@ -DHCP Performance Guide

    DHCP Performance Guide

    Tomasz Mrugalski

    This is a companion document for BIND 10 version +DHCP Performance Guide

    DHCP Performance Guide

    Tomasz Mrugalski

    This is a companion document for BIND 10 version 20120712.

    Abstract

    BIND 10 is a framework that features Domain Name System (DNS) and Dynamic Host Configuration Protocol (DHCP) software with development managed by Internet Systems Consortium (ISC). This document describes various aspects of DHCP performance, measurements and tuning. It covers BIND 10 DHCP (codename Kea), existing ISC DHCP4 software, perfdhcp (a DHCP performance - measurement tool) and other related topics.


    Preface

    Table of Contents

    1. Acknowledgements

    1. Acknowledgements

    ISC would like to acknowledge generous support for + measurement tool) and other related topics.


    Preface

    Table of Contents

    1. Acknowledgements

    1. Acknowledgements

    ISC would like to acknowledge generous support for BIND 10 development of DHCPv4 and DHCPv6 components provided by Comcast.

    Chapter 1. Introduction

    This document is in the early stages of development. It is @@ -14,9 +14,9 @@ tools, and the pros an cons of various optimization techniques.

    Chapter 2. ISC DHCP 4.x

    TODO: Write something about ISC DHCP4 here. -

    Chapter 3. Kea

    -

    3.1. Backend performance evaluation

    +

    3.1. Backend performance evaluation

    Kea will support several different database backends, using both popular databases (like MySQL or SQLite) and custom-developed solutions (such as an in-memory database). @@ -37,21 +37,20 @@ for performance measurements.

    All benchmarks are implemented as single threaded applications that take advantage of a single database connection.

    - Those benchmarks are stored in tests/tools/dhcp-ubench - directory of the BIND 10 source tree. This directory contains simplified prototypes for + Those benchmarks are stored in tests/tools/dhcp-ubench directory of the + BIND 10 source tree. This directory contains simplified prototypes for the various database back-ends that are planned or considered as a - possibly for BIND10 DHCP. Athough trivial now, the benchmarks are - expected to evolve into useful tools that will allow users to - measure performance in their specific environment. + possibly for BIND10 DHCP. These benchmarks are expected to evolve into + useful tools that will allow users to measure performance in their + specific environment.

    Currently the following benchmarks are implemented:

    • In memory + flat file

    • SQLite

    • MySQL

    - As the benchmarks require additional (sometimes heavy) dependencies, they are not - built by default. Actually, their build system is completely separate from that - of the rest of BIND 10. - It is anticipated that they will be eventually merged into the rest of BIND 10, but - that is a low priority for now. + As the benchmarks require additional (sometimes heavy) dependencies, they + are not built by default. Actually, their build system is completely + separate from that of the rest of BIND 10. It will be eventually merged + with the main BIND 10 build system.

    All benchmarks will follow the same pattern:

    1. Prepare operation (connect to a database, create a file etc.)

    2. Measure timestamp 0

    3. Commit new lease4 record (repeated N times)

    4. Measure timestamp 1

    5. Search for random lease4 record (repeated N times)

    6. Measure timestamp 2

    7. Update existing lease4 record (repeated N times)

    8. Measure timestamp 3

    9. Delete existing lease4 record (repeated N times)

    10. Measure timestamp 4

    11. Print out statistics, based on N and measured timestamps.

    @@ -95,31 +94,19 @@ the same list of parameters, some of them are specific to a given backend. To get a list of supported parameters, run the benchmark with the "-h" option: -

    $ ./mysql_ubench -h
    -This is a benchmark designed to measure expected performance
    -of several backends. This particular version identifies itself
    -as following:
    -MySQL client version is 5.5.24
    -
    -Possible command-line parameters:
    - -h - help (you are reading this)
    - -m hostname - specifies MySQL server to connect (MySQL backend only)
    - -u username - specifies MySQL user name (MySQL backend only)
    - -p password - specifies MySQL passwod (MySQL backend only)
    - -f name - database or filename (MySQL, SQLite and memfile)
    - -n integer - number of test repetitions (MySQL, SQLite and memfile)
    - -s yes|no - synchronous/asynchronous operation (MySQL, SQLite and memfile)
    - -v yes|no - verbose mode (MySQL, SQLite and memfile)
    - -c yes|no - should compiled statements be used (MySQL only)
    -

    - +

    $ ./mysql_ubench -h

    Synchronous operation requires database backend to physically store changes to disk before proceeding. This property ensures that no data is lost in case of the server failure. Unfortunately, it slows operation considerably. Asynchronous mode allows database to write data at a later time (usually controlled by the database engine on OS - disk buffering mechanism).

    3.2.1. MySQL tweaks

    One parameter that has huge impact on performance is the choice of backend engine. + disk buffering mechanism).

    3.2.1. MySQL tweaks

    To modify the default mysql_ubench parameters, command line + switches can be used. The currently supported switches are + (default values specified in brackets): +

    1. -f name - name of the database ("kea")

    2. -m hostname - name of the database host ("localhost")

    3. -u user - MySQL username ("root")

    4. -p password - MySQL password ("secret")

    5. -n num - number of iterations (100)

    6. -s yes|no - should the operations be performed in a synchronous (yes) + or asynchronous (no) manner (yes)

    7. -v yes|no - verbose mode. Should the test print out progress? (yes)

    8. -c yes|no - precompiled statements. Should the SQL statements be precompiled? (yes)

    +

    One parameter that has huge impact on performance is the choice of backend engine. You can get a list of engines of your MySQL implementation by using

    > show engines;

    @@ -151,7 +138,7 @@ Possible command-line parameters: switches can be used. The currently supported switches are (default values specified in brackets):

    1. -f filename - name of the database file ("sqlite.db")

    2. -n num - number of iterations (100)

    3. -s yes|no - should the operations be performed in a synchronous (yes) - or asynchronous (no) manner (yes)

    4. -v yes|no - verbose mode. Should the test print out progress? (yes)

    5. -c yes|no - precompiled statements. Should the SQL statements be precompiled?

    + or asynchronous (no) manner (yes)

  • -v yes|no - verbose mode. Should the test print out progress? (yes)

  • -c yes|no - precompiled statements. Should the SQL statements be precompiled? (yes)

  • SQLite can run in asynchronous or synchronous mode. This mode can be controlled by using "synchronous" parameter. It is set using the SQLite command:

    PRAGMA synchronous = ON|OFF

    Another tweakable feature is journal mode. It can be @@ -169,7 +156,14 @@ Possible command-line parameters: that file append operation is faster than modifications introduced in the middle of the file (as it often requires moving all data after modified point, effectively requiring writing large parts of - the whole file, not just changed fragment).

    3.4.1. memfile tweaks

    To modify default memfile_ubench parameters, command line + the whole file, not just changed fragment).

    There are no preparatory steps required for memfile benchmark. + The only requirement is the ability to create and write specified lease + file (dhcpd.leases in the current directory). The tests can be run + as follows: +

    > ./memfile_ubench

    + or +

    > ./memfile_ubench > results-memfile.txt

    +

    3.4.1. memfile tweaks

    To modify default memfile_ubench parameters, command line switches can be used. Currently supported switches are (default values specified in brackets):

    1. -f filename - name of the database file ("dhcpd.leases")

    2. -n num - number of iterations (100)

    3. -s yes|no - should the operations be performend in a synchronous (yes) @@ -177,7 +171,7 @@ Possible command-line parameters:

      memfile can run in asynchronous or synchronous mode. This mode can be controlled by using sync parameter. It uses fflush() and fsync() in synchronous mode to make sure that - data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, + data is not buffered and physically stored on disk.

    3.5. Basic performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    @@ -192,13 +186,12 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
           asynchronous. As those modes offer radically different
           performances, synchronous mode was conducted for one
           thousand repetitions and asynchronous mode was conducted for
    -      one hundred thousand repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00031.604 0.11727.96427.69521.845
    SQLite1,00061.421 0.03359.47756.03444.241
    memfile1,00038.224 0.00138.04138.01728.571

    The following parameters were measured for asynchronous mode. - MySQL and SQLite were run with one hundred thousand repetitions. Memfile - was run for one million repetitions due to its much higher performance.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,00010.58510.38610.062 8.890 9.981
    SQLite100,000 3.710 3.159 2.865 2.439 3.044
    memfile1,000,000 1.300 0.039 1.307 1.278 0.981

    The presented performance results can be converted into operations per second metrics. + one hundred thousand repetitions.

    Table 3.1. Synchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00031.604 0.11727.96427.69521.845
    SQLite1,00061.421 0.03359.47756.03444.241
    memfile1,00038.224 0.00138.04138.01728.571

    The following parameters were measured for asynchronous mode. + MySQL and SQLite were run with one hundred thousand repetitions.

    Table 3.2. Asynchronous results (basic)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,00010.58510.38610.062 8.890 9.981
    SQLite100,000 3.710 3.159 2.865 2.439 3.044
    memfile100,000 1.300 0.039 1.307 1.278 0.981

    The presented performance results can be converted into operations per second metrics. It should be noted that due to large differences between various operations (sometimes over three orders of magnitude), it is difficult to create a simple, readable chart with - that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Basic performance measurements

    Graphical representation of the basic performance results - presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, + that data.

    Table 3.3. Estimated basic performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)9447.479627.979938.0011248.3410065.45
    SQLite (async)26951.5931654.2934899.7040993.5933624.79
    memfile (async)76944.272542588.3576504.5478269.25693576.60
    MySQL (sync)31.648575.4535.7636.112169.74
    SQLite (sync)16.2820045.3716.8117.857524.08
    memfile (sync)26.161223990.2126.2926.30306017.24

    Graphical representation of the basic performance results + presented in table Table 3.3, “Estimated basic performance”.

    3.6. Optimized performance measurements

    This section contains sample results for backend performance measurements, taken using microbenchmarks. Tests were conducted on reasonably powerful machine:

     CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
    @@ -213,13 +206,12 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
           asynchronous. As those modes offer radically different
           performances, synchronous mode was conducted for one
           thousand repetitions and asynchronous mode was conducted for
    -      one hundred thousand repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00027.887 0.10628.22327.69620.978
    SQLite1,00061.299 0.01559.64861.09845.626
    memfile1,00039.564 0.00139.54339.32629.608

    The following parameters were measured for asynchronous mode. - MySQL and SQLite were run with one hundred thousand repetitions. Memfile - was run for one million repetitions due to its much higher performance.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,0008.5079.6987.7858.3268.579
    SQLite100,000 1.562 0.949 1.513 1.502 1.382
    memfile1,000,0001.3020.0381.3061.2630.977

    The presented performance results can be converted into operations per second metrics. + one hundred thousand repetitions.

    Table 3.4. Synchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL1,00027.887 0.10628.22327.69620.978
    SQLite1,00061.299 0.01559.64861.09845.626
    memfile1,00039.564 0.00139.54339.32629.608

    The following parameters were measured for asynchronous mode. + MySQL and SQLite were run with one hundred thousand repetitions.

    Table 3.5. Asynchronous results (optimized)

    BackendOperationsCreate [s]Search [s]Update [s]Delete [s]Average [s]
    MySQL100,0008.5079.6987.7858.3268.579
    SQLite100,000 1.562 0.949 1.513 1.502 1.382
    memfile100,0001.3020.0381.3061.2630.977

    The presented performance results can be converted into operations per second metrics. It should be noted that due to large differences between various operations (sometime over three orders of magnitude), it is difficult to create a simple, readable chart with the data.

    Table 3.6. Estimated optimized performance

    BackendCreate [oper/s]Search [oper/s]Update [oper/s]Delete [oper/s]Average [oper/s]
    MySQL (async)11754.8410311.3412845.3512010.2411730.44
    SQLite (async)64005.90105391.2966075.5166566.4375509.78
    memfile (async)76832.162636018.5676542.5079188.81717145.51
    MySQL (sync)35.869461.1035.4336.112392.12
    SQLite (sync)16.3167036.1116.7616.3716771.39
    memfile (sync)25.283460207.6125.2925.43865070.90

    Optimized performance measurements

    Graphical representation of the optimized performance - results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    + results presented in table Table 3.6, “Estimated optimized performance”.

    3.7. Conclusions

    Improvements gained by introducing support for precompiled statements in MySQL is somewhat disappointing - between 6 and 29%. On the other hand, the improvement in SQLite is @@ -238,12 +230,13 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 factor here is a disk access time. Even migrating to high performance 15,000 rpm disk is expected to only roughly double number of leases per second, compared to the current results. - The reason is that to write a file to disk, at least two writes + The reason is that to write a file to disk, at least two disk + sector writes are required: the new content and i-node modification of the file. The easiest way to boost synchronous performance is to switch to SSD disks. Memory-backed RAM disks are also a viable solution. However, care should be taken to properly engineer - backup strategy for RAM disks. + backup strategy for such RAM disks.

    While the custom made backend (memfile) provides the best perfomance, it carries over all the limitations existing in @@ -267,7 +260,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 message. The provided results should be considered as only rough estimates. They can also be used for relative comparisons between backends. -

    3.8. Possible further optimizations

    +

    3.8. Possible further optimizations

    For basic measurements the code was compiled with -g -O0 flags. For optimized measurements the benchmarking code was compiled with -Ofast (optimize for speed). In both cases, the diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml index 6e3846731d..2bfe9bff90 100644 --- a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml +++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml @@ -120,12 +120,12 @@ that take advantage of a single database connection. - Those benchmarks are stored in tests/tools/dhcp-ubench - directory of the BIND 10 source tree. This directory contains simplified prototypes for + Those benchmarks are stored in tests/tools/dhcp-ubench directory of the + BIND 10 source tree. This directory contains simplified prototypes for the various database back-ends that are planned or considered as a - possibly for BIND10 DHCP. Athough trivial now, the benchmarks are - expected to evolve into useful tools that will allow users to - measure performance in their specific environment. + possibly for BIND10 DHCP. These benchmarks are expected to evolve into + useful tools that will allow users to measure performance in their + specific environment. @@ -138,11 +138,10 @@ - As the benchmarks require additional (sometimes heavy) dependencies, they are not - built by default. Actually, their build system is completely separate from that - of the rest of BIND 10. - It is anticipated that they will be eventually merged into the rest of BIND 10, but - that is a low priority for now. + As the benchmarks require additional (sometimes heavy) dependencies, they + are not built by default. Actually, their build system is completely + separate from that of the rest of BIND 10. It will be eventually merged + with the main BIND 10 build system. @@ -188,10 +187,10 @@ Before running tests, you need to initialize your database. You can use mysql.schema script for that purpose. - + WARNING: It will drop existing Kea database. Do not run this on your production server. - + Assuming your MySQL user is "kea", you can initialize your test database by: @@ -217,24 +216,7 @@ the same list of parameters, some of them are specific to a given backend. To get a list of supported parameters, run the benchmark with the "-h" option: - $ ./mysql_ubench -h -This is a benchmark designed to measure expected performance -of several backends. This particular version identifies itself -as following: -MySQL client version is 5.5.24 - -Possible command-line parameters: - -h - help (you are reading this) - -m hostname - specifies MySQL server to connect (MySQL backend only) - -u username - specifies MySQL user name (MySQL backend only) - -p password - specifies MySQL passwod (MySQL backend only) - -f name - database or filename (MySQL, SQLite and memfile) - -n integer - number of test repetitions (MySQL, SQLite and memfile) - -s yes|no - synchronous/asynchronous operation (MySQL, SQLite and memfile) - -v yes|no - verbose mode (MySQL, SQLite and memfile) - -c yes|no - should compiled statements be used (MySQL only) - - + $ ./mysql_ubench -h Synchronous operation requires database backend to @@ -248,6 +230,23 @@ Possible command-line parameters:

    MySQL tweaks + To modify the default mysql_ubench parameters, command line + switches can be used. The currently supported switches are + (default values specified in brackets): + + -f name - name of the database ("kea") + -m hostname - name of the database host ("localhost") + -u user - MySQL username ("root") + -p password - MySQL password ("secret") + -n num - number of iterations (100) + -s yes|no - should the operations be performed in a synchronous (yes) + or asynchronous (no) manner (yes) + -v yes|no - verbose mode. Should the test print out progress? (yes) + -c yes|no - precompiled statements. Should the SQL statements be precompiled? (yes) + + + + One parameter that has huge impact on performance is the choice of backend engine. You can get a list of engines of your MySQL implementation by using @@ -300,14 +299,14 @@ Possible command-line parameters: -s yes|no - should the operations be performed in a synchronous (yes) or asynchronous (no) manner (yes) -v yes|no - verbose mode. Should the test print out progress? (yes) - -c yes|no - precompiled statements. Should the SQL statements be precompiled? + -c yes|no - precompiled statements. Should the SQL statements be precompiled? (yes) SQLite can run in asynchronous or synchronous mode. This mode can be controlled by using "synchronous" parameter. It is set using the SQLite command: - + PRAGMA synchronous = ON|OFF Another tweakable feature is journal mode. It can be @@ -334,6 +333,15 @@ Possible command-line parameters: after modified point, effectively requiring writing large parts of the whole file, not just changed fragment). + There are no preparatory steps required for memfile benchmark. + The only requirement is the ability to create and write specified lease + file (dhcpd.leases in the current directory). The tests can be run + as follows: + > ./memfile_ubench + or + > ./memfile_ubench > results-memfile.txt + +
    memfile tweaks To modify default memfile_ubench parameters, command line @@ -435,8 +443,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 The following parameters were measured for asynchronous mode. - MySQL and SQLite were run with one hundred thousand repetitions. Memfile - was run for one million repetitions due to its much higher performance. + MySQL and SQLite were run with one hundred thousand repetitions. Asynchronous results (basic) @@ -482,7 +489,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile - 1,000,000 + 100,000 1.300 0.039 1.307 @@ -577,13 +584,21 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
    + + + + - + - - Basic performance measurements - Graphical representation of the basic performance results presented in table . @@ -672,8 +687,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 The following parameters were measured for asynchronous mode. - MySQL and SQLite were run with one hundred thousand repetitions. Memfile - was run for one million repetitions due to its much higher performance. + MySQL and SQLite were run with one hundred thousand repetitions. Asynchronous results (optimized) @@ -719,7 +733,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 memfile - 1,000,000 + 100,000 1.302 0.038 1.306 @@ -855,12 +869,13 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7 factor here is a disk access time. Even migrating to high performance 15,000 rpm disk is expected to only roughly double number of leases per second, compared to the current results. - The reason is that to write a file to disk, at least two writes + The reason is that to write a file to disk, at least two disk + sector writes are required: the new content and i-node modification of the file. The easiest way to boost synchronous performance is to switch to SSD disks. Memory-backed RAM disks are also a viable solution. However, care should be taken to properly engineer - backup strategy for RAM disks. + backup strategy for such RAM disks. From d8dd6f7cb2a0118d692c924d5652d5ec84906117 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 11 Sep 2012 16:17:37 +0200 Subject: [PATCH 124/148] [2231] Implemented sub-second timeouts for IfaceMgr::receiveX functions. --- src/lib/dhcp/iface_mgr.cc | 20 ++--- src/lib/dhcp/iface_mgr.h | 14 +-- src/lib/dhcp/tests/iface_mgr_unittest.cc | 106 +++++++++++++++++++++++ 3 files changed, 124 insertions(+), 16 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 90f6353622..cff9f12b2d 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -1,4 +1,4 @@ -// Copyright (C) 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 // purpose with or without fee is hereby granted, provided that the above @@ -785,7 +785,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt) boost::shared_ptr -IfaceMgr::receive4(uint32_t timeout) { +IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) { const SocketInfo* candidate = 0; IfaceCollection::const_iterator iface; @@ -825,13 +825,12 @@ IfaceMgr::receive4(uint32_t timeout) { names << session_socket_ << "(session)"; } - /// @todo: implement sub-second precision one day struct timeval select_timeout; - select_timeout.tv_sec = timeout; - select_timeout.tv_usec = 0; + select_timeout.tv_sec = timeout_sec; + select_timeout.tv_usec = timeout_usec; cout << "Trying to receive data on sockets: " << names.str() - << ". Timeout is " << timeout << " seconds." << endl; + << ". Timeout is " << timeout_sec << " seconds." << endl; int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout); cout << "select returned " << result << endl; @@ -953,7 +952,7 @@ IfaceMgr::receive4(uint32_t timeout) { return (pkt); } -Pkt6Ptr IfaceMgr::receive6(uint32_t timeout) { +Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec) { const SocketInfo* candidate = 0; fd_set sockets; @@ -994,12 +993,11 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout) { } cout << "Trying to receive data on sockets:" << names.str() - << ".Timeout is " << timeout << " seconds." << endl; + << ".Timeout is " << timeout_sec << " seconds." << endl; - /// @todo: implement sub-second precision one day struct timeval select_timeout; - select_timeout.tv_sec = timeout; - select_timeout.tv_usec = 0; + select_timeout.tv_sec = timeout_sec; + select_timeout.tv_usec = timeout_usec; int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout); diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index 36ad0eada2..cbc254b65d 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -1,4 +1,4 @@ -// Copyright (C) 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 // purpose with or without fee is hereby granted, provided that the above @@ -345,10 +345,12 @@ public: /// to not wait infinitely, but rather do something useful /// (e.g. remove expired leases) /// - /// @param timeout specifies timeout (in seconds) + /// @param timeout_sec specifies integral part of the timeout (in seconds) + /// @param timeout_usec specifies fractional part of the timeout + /// (in microseconds) /// /// @return Pkt6 object representing received packet (or NULL) - Pkt6Ptr receive6(uint32_t timeout); + Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0); /// @brief Tries to receive IPv4 packet over open IPv4 sockets. /// @@ -356,10 +358,12 @@ public: /// If reception is successful and all information about its sender /// are obtained, Pkt4 object is created and returned. /// - /// @param timeout specifies timeout (in seconds) + /// @param timeout_sec specifies integral part of the timeout (in seconds) + /// @param timeout_usec specifies fractional part of the timeout + /// (in microseconds) /// /// @return Pkt4 object representing received packet (or NULL) - Pkt4Ptr receive4(uint32_t timeout); + Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0); /// Opens UDP/IP socket and binds it to address, interface and port. /// diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 5562551a0e..3a05651529 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -217,6 +217,112 @@ TEST_F(IfaceMgrTest, getIface) { } +TEST_F(IfaceMgrTest, receiveTimeout6) { + std::cout << "Testing DHCPv6 packet reception timeouts." + << " Test will block for a few seconds when waiting" + << " for timeout to occur." << std::endl; + + boost::scoped_ptr ifacemgr(new NakedIfaceMgr()); + // Open socket on the lo interface. + IOAddress loAddr("::1"); + int socket1 = 0; + ASSERT_NO_THROW( + socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547) + ); + // Socket is open if its descriptor is greater than zero. + ASSERT_GT(socket1, 0); + + // Time when call to IfaceMgr::receive6() started. + timeval start_time; + // Time when call to IfaceMgr::receive6() ended. + timeval stop_time; + + // Remember when we call receive6(). + gettimeofday(&start_time, NULL); + // Call receive with timeout of 1s + 1000us. + Pkt6Ptr pkt = ifacemgr->receive6(1, 1000); + // Remember when call to receive6() ended. + gettimeofday(&stop_time, NULL); + // We did not send a packet to lo interface so we expect that + // nothing has been received and timeout has been reached. + ASSERT_FALSE(pkt); + // Calculate duration of call to receive6(). + stop_time.tv_sec -= start_time.tv_sec; + stop_time.tv_usec -= start_time.tv_usec; + // Duration should be equal or greater than timeout specified + // for the receive6() call. + EXPECT_EQ(stop_time.tv_sec, 1); + EXPECT_GT(stop_time.tv_usec, 1000); + + // Test timeout shorter than 1s. + gettimeofday(&start_time, NULL); + pkt = ifacemgr->receive6(0, 500); + gettimeofday(&stop_time, NULL); + ASSERT_FALSE(pkt); + stop_time.tv_sec -= start_time.tv_sec; + stop_time.tv_usec -= start_time.tv_usec; + // The timeout has been set to 500us. Even though the way we measure + // duration of receive6() may result in durations slightly longer than + // timeout it is safe to assume that measured value will not exceed 1s + // when timeout is only 500us. If it exceeds, this is an error and + // should be investigated. + EXPECT_EQ(0, stop_time.tv_sec); + EXPECT_GT(stop_time.tv_usec, 500); +} + +TEST_F(IfaceMgrTest, receiveTimeout4) { + std::cout << "Testing DHCPv6 packet reception timeouts." + << " Test will block for a few seconds when waiting" + << " for timeout to occur." << std::endl; + + boost::scoped_ptr ifacemgr(new NakedIfaceMgr()); + // Open socket on the lo interface. + IOAddress loAddr("127.0.0.1"); + int socket1 = 0; + ASSERT_NO_THROW( + socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10067) + ); + // Socket is open if its descriptor is greater than zero. + ASSERT_GT(socket1, 0); + + // Time when call to IfaceMgr::receive4() started. + timeval start_time; + // Time when call to IfaceMgr::receive4() ended. + timeval stop_time; + + // Remember when we call receive4(). + gettimeofday(&start_time, NULL); + // Call receive with timeout of 2s + 150us. + Pkt4Ptr pkt = ifacemgr->receive4(2, 150); + // Remember when call to receive4() ended. + gettimeofday(&stop_time, NULL); + // We did not send a packet to lo interface so we expect that + // nothing has been received and timeout has been reached. + ASSERT_FALSE(pkt); + // Calculate duration of call to receive4(). + stop_time.tv_sec -= start_time.tv_sec; + stop_time.tv_usec -= start_time.tv_usec; + // Duration should be equal or greater than timeout specified + // for the receive4() call. + EXPECT_EQ(stop_time.tv_sec, 2); + EXPECT_GT(stop_time.tv_usec, 150); + + // Test timeout shorter than 1s. + gettimeofday(&start_time, NULL); + pkt = ifacemgr->receive4(0, 350); + gettimeofday(&stop_time, NULL); + ASSERT_FALSE(pkt); + stop_time.tv_sec -= start_time.tv_sec; + stop_time.tv_usec -= start_time.tv_usec; + // The timeout has been set to 350us. Even though the way we measure + // duration of receive4() may result in durations slightly longer than + // timeout it is safe to assume that measured value will not exceed 1s + // when timeout is only 350us. If it exceeds, this is an error and + // should be investigated. + EXPECT_EQ(0, stop_time.tv_sec); + EXPECT_GT(stop_time.tv_usec, 350); +} + TEST_F(IfaceMgrTest, sockets6) { // testing socket operation in a portable way is tricky // without interface detection implemented From b0414cf54bb6c446c98c3e791d3212b02ff50c8f Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 11 Sep 2012 17:25:52 +0200 Subject: [PATCH 125/148] [2231] Added sanity check for microsecond timeout. --- src/lib/dhcp/iface_mgr.cc | 11 ++++++++++- src/lib/dhcp/iface_mgr.h | 2 ++ src/lib/dhcp/tests/iface_mgr_unittest.cc | 18 ++++++++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index cff9f12b2d..0c99647e27 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -786,7 +786,11 @@ IfaceMgr::send(const Pkt4Ptr& pkt) boost::shared_ptr IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) { - + // Sanity check for microsecond timeout. + if (timeout_usec >= 1000000) { + isc_throw(BadValue, "fractional timeout must be shorter than" + " one million microseconds"); + } const SocketInfo* candidate = 0; IfaceCollection::const_iterator iface; fd_set sockets; @@ -953,6 +957,11 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) { } Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec) { + // Sanity check for microsecond timeout. + if (timeout_usec >= 1000000) { + isc_throw(BadValue, "fractional timeout must be shorter than" + " one million microseconds"); + } const SocketInfo* candidate = 0; fd_set sockets; diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index cbc254b65d..922c701733 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -349,6 +349,7 @@ public: /// @param timeout_usec specifies fractional part of the timeout /// (in microseconds) /// + /// @throw isc::BadValue if timeout_usec is greater than one million /// @return Pkt6 object representing received packet (or NULL) Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0); @@ -362,6 +363,7 @@ public: /// @param timeout_usec specifies fractional part of the timeout /// (in microseconds) /// + /// @throw isc::BadValue if timeout_usec is greater than one million /// @return Pkt4 object representing received packet (or NULL) Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0); diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 3a05651529..3076658a6f 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -240,7 +240,8 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { // Remember when we call receive6(). gettimeofday(&start_time, NULL); // Call receive with timeout of 1s + 1000us. - Pkt6Ptr pkt = ifacemgr->receive6(1, 1000); + Pkt6Ptr pkt; + ASSERT_NO_THROW(pkt = ifacemgr->receive6(1, 1000)); // Remember when call to receive6() ended. gettimeofday(&stop_time, NULL); // We did not send a packet to lo interface so we expect that @@ -256,7 +257,7 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { // Test timeout shorter than 1s. gettimeofday(&start_time, NULL); - pkt = ifacemgr->receive6(0, 500); + ASSERT_NO_THROW(pkt = ifacemgr->receive6(0, 500)); gettimeofday(&stop_time, NULL); ASSERT_FALSE(pkt); stop_time.tv_sec -= start_time.tv_sec; @@ -268,6 +269,10 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { // should be investigated. EXPECT_EQ(0, stop_time.tv_sec); EXPECT_GT(stop_time.tv_usec, 500); + + // Test with invalid fractional timeout values. + EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); + EXPECT_THROW(ifacemgr->receive6(1, 1000010), isc::BadValue); } TEST_F(IfaceMgrTest, receiveTimeout4) { @@ -293,7 +298,8 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { // Remember when we call receive4(). gettimeofday(&start_time, NULL); // Call receive with timeout of 2s + 150us. - Pkt4Ptr pkt = ifacemgr->receive4(2, 150); + Pkt4Ptr pkt; + ASSERT_NO_THROW(pkt = ifacemgr->receive4(2, 150)); // Remember when call to receive4() ended. gettimeofday(&stop_time, NULL); // We did not send a packet to lo interface so we expect that @@ -309,7 +315,7 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { // Test timeout shorter than 1s. gettimeofday(&start_time, NULL); - pkt = ifacemgr->receive4(0, 350); + ASSERT_NO_THROW(pkt = ifacemgr->receive4(0, 350)); gettimeofday(&stop_time, NULL); ASSERT_FALSE(pkt); stop_time.tv_sec -= start_time.tv_sec; @@ -321,6 +327,10 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { // should be investigated. EXPECT_EQ(0, stop_time.tv_sec); EXPECT_GT(stop_time.tv_usec, 350); + + // Test with invalid fractional timeout values. + EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); + EXPECT_THROW(ifacemgr->receive6(2, 1000005), isc::BadValue); } TEST_F(IfaceMgrTest, sockets6) { From 0c9ad616b7ce975f9cf0b26241c3a993f870c2b9 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 11 Sep 2012 18:00:02 +0200 Subject: [PATCH 126/148] [master] Improved DHCP Performance Guide generation. --- tests/tools/dhcp-ubench/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tools/dhcp-ubench/Makefile b/tests/tools/dhcp-ubench/Makefile index 599c4f69a1..16735e9972 100644 --- a/tests/tools/dhcp-ubench/Makefile +++ b/tests/tools/dhcp-ubench/Makefile @@ -62,4 +62,4 @@ dhcp-perf-guide.html: dhcp-perf-guide.xml version.ent dhcp-perf-guide.xml dhcp-perf-guide.pdf: dhcp-perf-guide.xml - docbook2pdf $< + dblatex -P doc.collab.show=0 -P latex.output.revhistory=0 $< From 1b84c5e9b4391869185ceb41195b462f553b4f25 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 11 Sep 2012 21:19:47 +0200 Subject: [PATCH 127/148] [1959] Removed using namespece boost in TestControl. This is supposed to resolve ambiguous uintX_t types on Solaris 11. --- tests/tools/perfdhcp/test_control.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc index 090fb32411..c154cf9ceb 100644 --- a/tests/tools/perfdhcp/test_control.cc +++ b/tests/tools/perfdhcp/test_control.cc @@ -34,7 +34,6 @@ #include "perf_pkt6.h" using namespace std; -using namespace boost; using namespace boost::posix_time; using namespace isc; using namespace isc::dhcp; @@ -1123,11 +1122,11 @@ TestControl::sendDiscover4(const TestControlSocket& socket, // Replace MAC address in the template with actual MAC address. pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end()); // Create a packet from the temporary buffer. - setDefaults4(socket, static_pointer_cast(pkt4)); + setDefaults4(socket, boost::static_pointer_cast(pkt4)); // Pack the input packet buffer to output buffer so as it can // be sent to server. pkt4->rawPack(); - IfaceMgr::instance().send(static_pointer_cast(pkt4)); + IfaceMgr::instance().send(boost::static_pointer_cast(pkt4)); if (!preload) { if (!stats_mgr4_) { isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " @@ -1135,7 +1134,7 @@ TestControl::sendDiscover4(const TestControlSocket& socket, } // Update packet stats. stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO, - static_pointer_cast(pkt4)); + boost::static_pointer_cast(pkt4)); } } @@ -1308,17 +1307,17 @@ TestControl::sendRequest4(const TestControlSocket& socket, opt_requested_ip->setUint32(static_cast(yiaddr)); pkt4->addOption(opt_requested_ip); - setDefaults4(socket, static_pointer_cast(pkt4)); + setDefaults4(socket, boost::static_pointer_cast(pkt4)); // Prepare on-wire data. pkt4->rawPack(); - IfaceMgr::instance().send(static_pointer_cast(pkt4)); + IfaceMgr::instance().send(boost::static_pointer_cast(pkt4)); if (!stats_mgr4_) { isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 " "hasn't been initialized"); } // Update packet stats. stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA, - static_pointer_cast(pkt4)); + boost::static_pointer_cast(pkt4)); } void @@ -1435,7 +1434,7 @@ TestControl::sendRequest6(const TestControlSocket& socket, } // Set IA_NA boost::shared_ptr opt_ia_na_advertise = - static_pointer_cast(advertise_pkt6->getOption(D6O_IA_NA)); + boost::static_pointer_cast(advertise_pkt6->getOption(D6O_IA_NA)); if (!opt_ia_na_advertise) { isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received " "packet"); From 1a4c5a70d4917bd1942d5f940bfaf0a1e35b6a0f Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 12 Sep 2012 11:09:09 +0200 Subject: [PATCH 128/148] [1959] Include command_options_helper.h in Makefile. --- tests/tools/perfdhcp/tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tools/perfdhcp/tests/Makefile.am b/tests/tools/perfdhcp/tests/Makefile.am index 0cbeb8a456..73ec6babc5 100644 --- a/tests/tools/perfdhcp/tests/Makefile.am +++ b/tests/tools/perfdhcp/tests/Makefile.am @@ -23,6 +23,7 @@ run_unittests_SOURCES += perf_pkt4_unittest.cc run_unittests_SOURCES += localized_option_unittest.cc run_unittests_SOURCES += stats_mgr_unittest.cc run_unittests_SOURCES += test_control_unittest.cc +run_unittests_SOURCES += command_options_helper.h run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/command_options.cc run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/pkt_transform.cc run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt6.cc From 45ca30e42d6f87bd1039cbcd7f83dfa15ebdcfa0 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 12 Sep 2012 11:16:17 +0200 Subject: [PATCH 129/148] [1959] Test opening socket from remote broadcast address on Linux only. In order to run this test interface detection is required. Since it is right now implemented on Linux only it had to be disabled on every other OS. --- src/lib/dhcp/iface_mgr.cc | 5 +++++ src/lib/dhcp/tests/iface_mgr_unittest.cc | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 9c03794c2d..be17b09b5d 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -513,6 +513,7 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) { } sock.set_option(asio::socket_base::broadcast(true), err_code); if (err_code) { + sock.close(); isc_throw(Unexpected, "failed to enable broadcast on the socket"); } } @@ -520,6 +521,7 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) { // Try to connect to remote endpoint and check if attempt is successful. sock.connect(remote_endpoint->getASIOEndpoint(), err_code); if (err_code) { + sock.close(); isc_throw(Unexpected,"failed to connect to remote endpoint."); } @@ -528,6 +530,9 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) { sock.local_endpoint(); asio::ip::address local_address(local_endpoint.address()); + // Close the socket. + sock.close(); + // Return address of local endpoint. return IOAddress(local_address); } diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 7f8555c1fa..ad8dba905b 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -407,6 +407,11 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) { EXPECT_GT(socket2, 0); close(socket2); + // The following test is currently disabled for OSes other than + // Linux because interface detection is not implemented on them. + // @todo enable this test for all OSes once interface detection + // is implemented. +#if defined(OS_LINUX) // Open v4 socket to connect to broadcast address. int socket3 = 0; IOAddress bcastAddr("255.255.255.255"); @@ -415,6 +420,7 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) { ); EXPECT_GT(socket3, 0); close(socket3); +#endif } // TODO: disabled due to other naming on various systems From 9ddbc590eab2267c8c7b98f1c41f5d75d81a860c Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 12 Sep 2012 13:39:47 +0200 Subject: [PATCH 130/148] [1959] Included perfdhcp/templates folder in Makefiles. --- configure.ac | 1 + tests/tools/perfdhcp/Makefile.am | 2 +- tests/tools/perfdhcp/templates/Makefile.am | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/tools/perfdhcp/templates/Makefile.am diff --git a/configure.ac b/configure.ac index e75cbd8d3b..5368514353 100644 --- a/configure.ac +++ b/configure.ac @@ -1199,6 +1199,7 @@ AC_CONFIG_FILES([Makefile tests/tools/badpacket/tests/Makefile tests/tools/perfdhcp/Makefile tests/tools/perfdhcp/tests/Makefile + tests/tools/perfdhcp/templates/Makefile dns++.pc ]) AC_OUTPUT([doc/version.ent diff --git a/tests/tools/perfdhcp/Makefile.am b/tests/tools/perfdhcp/Makefile.am index 53bc539d9d..0532f27dcc 100644 --- a/tests/tools/perfdhcp/Makefile.am +++ b/tests/tools/perfdhcp/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . tests +SUBDIRS = . tests templates AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log diff --git a/tests/tools/perfdhcp/templates/Makefile.am b/tests/tools/perfdhcp/templates/Makefile.am new file mode 100644 index 0000000000..9253c6d449 --- /dev/null +++ b/tests/tools/perfdhcp/templates/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = . + +perfdhcp_DATA = discover-example.hex request4-example.hex \ + solicit-example.hex request6-example.hex From 9a3a5db5ee5cf4571a2c573e046faef0be07410f Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 12 Sep 2012 16:12:11 +0200 Subject: [PATCH 131/148] [1959] Minor corrections. --- tests/tools/perfdhcp/templates/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/tools/perfdhcp/templates/Makefile.am b/tests/tools/perfdhcp/templates/Makefile.am index 9253c6d449..4da2027903 100644 --- a/tests/tools/perfdhcp/templates/Makefile.am +++ b/tests/tools/perfdhcp/templates/Makefile.am @@ -1,4 +1,8 @@ SUBDIRS = . +perfdhcpdir = $(pkgdatadir) perfdhcp_DATA = discover-example.hex request4-example.hex \ solicit-example.hex request6-example.hex + +EXTRA_DIST = discover-example.hex request4-example.hex +EXTRA_DIST += solicit-example.hex request6-example.hex From c7a025395cf01c95cee3430fdd94256ab3350244 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Wed, 12 Sep 2012 15:32:58 +0100 Subject: [PATCH 132/148] [1545] Corrected copyright year in new/modified files --- src/bin/dhcp4/dhcp4_log.cc | 2 +- src/bin/dhcp4/dhcp4_log.h | 2 +- src/bin/dhcp4/dhcp4_messages.mes | 2 +- src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 2 +- src/bin/dhcp6/dhcp6_log.cc | 2 +- src/bin/dhcp6/dhcp6_log.h | 2 +- src/bin/dhcp6/dhcp6_messages.mes | 2 +- src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bin/dhcp4/dhcp4_log.cc b/src/bin/dhcp4/dhcp4_log.cc index 51c18df455..678223b134 100644 --- a/src/bin/dhcp4/dhcp4_log.cc +++ b/src/bin/dhcp4/dhcp4_log.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +// 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 diff --git a/src/bin/dhcp4/dhcp4_log.h b/src/bin/dhcp4/dhcp4_log.h index 9d05818f3f..3717b62d92 100644 --- a/src/bin/dhcp4/dhcp4_log.h +++ b/src/bin/dhcp4/dhcp4_log.h @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +// 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 diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index b149b25322..87b3d1a6f0 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -1,4 +1,4 @@ -# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +# 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 diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc index 08be95c47f..fca06ad988 100644 --- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 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 // purpose with or without fee is hereby granted, provided that the above diff --git a/src/bin/dhcp6/dhcp6_log.cc b/src/bin/dhcp6/dhcp6_log.cc index 9816f47b03..d89383492c 100644 --- a/src/bin/dhcp6/dhcp6_log.cc +++ b/src/bin/dhcp6/dhcp6_log.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +// 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 diff --git a/src/bin/dhcp6/dhcp6_log.h b/src/bin/dhcp6/dhcp6_log.h index 8db11dbad0..6d7f4e33b0 100644 --- a/src/bin/dhcp6/dhcp6_log.h +++ b/src/bin/dhcp6/dhcp6_log.h @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +// 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 diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes index f2e6fda2c9..f43bf09a6f 100644 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -1,4 +1,4 @@ -# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +# 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 diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 0e494e972b..f1ce8f704b 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 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 // purpose with or without fee is hereby granted, provided that the above @@ -268,4 +268,4 @@ TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) { } } -} // oF ANONYMOUS NAMESPACE +} // anonymous namespace From 23ba7abb4e2fe826bf536c822fb7eef20ebcd689 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Wed, 12 Sep 2012 15:58:00 +0100 Subject: [PATCH 133/148] [1545] Minor changes as suggested by review --- src/bin/dhcp4/dhcp4_messages.mes | 6 +++--- src/bin/dhcp4/dhcp4_srv.h | 10 +++++----- src/bin/dhcp6/dhcp6_messages.mes | 4 ++-- src/bin/dhcp6/dhcp6_srv.h | 6 +++--- src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 87b3d1a6f0..98e402da84 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -40,7 +40,7 @@ server is about to open sockets on the specified port. % DHCP4_PACKET_PARSE_FAIL failed to parse incoming packet: %1 The IPv4 DHCP server has received a packet that it is unable to -interpret. The reason why the packet is invalid is include in the message. +interpret. The reason why the packet is invalid is included in the message. % DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3 A debug message noting that the server has received the specified type of @@ -50,8 +50,8 @@ may well be a valid DHCP packet, just a type not expected by the server % DHCP4_PACK_FAIL failed to assemble response correctly This error is output if the server failed to assemble the data to be -returned to the client into a valid packet. Additional messages will -detail the reason. +returned to the client into a valid packet. The cause is most likely +to be a programming error: please raise a bug report. % DHCP4_QUERY_DATA received packet type %1, data is <%2> A debug message listing the data received from the client. diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h index ce09f5313f..f677259947 100644 --- a/src/bin/dhcp4/dhcp4_srv.h +++ b/src/bin/dhcp4/dhcp4_srv.h @@ -44,7 +44,7 @@ class Dhcpv4Srv : public boost::noncopyable { public: /// @brief Default constructor. /// - /// Instantiates necessary services, required to run DHCPv6 server. + /// Instantiates necessary services, required to run DHCPv4 server. /// In particular, creates IfaceMgr that will be responsible for /// network interaction. Will instantiate lease manager, and load /// old or create new DUID. It is possible to specify alternate @@ -54,7 +54,7 @@ class Dhcpv4Srv : public boost::noncopyable { /// @param port specifies port number to listen on Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT); - /// @brief Destructor. Used during DHCPv6 service shutdown. + /// @brief Destructor. Used during DHCPv4 service shutdown. ~Dhcpv4Srv(); /// @brief Main server processing loop. @@ -75,7 +75,7 @@ class Dhcpv4Srv : public boost::noncopyable { /// Returns the name of valid packet received by the server (e.g. DISCOVER). /// If the packet is unknown - or if it is a valid DHCP packet but not one /// expected to be received by the server (such as an OFFER), the string - /// "UNKNOWN" is returned. This methos is used in debug messages. + /// "UNKNOWN" is returned. This method is used in debug messages. /// /// As the operation of the method does not depend on any server state, it /// is declared static. @@ -106,11 +106,11 @@ protected: /// is valid, not expired, not reserved, not used by other client and /// that requesting client is allowed to use it. /// - /// Returns ACK message, NACK message, or NULL + /// Returns ACK message, NAK message, or NULL /// /// @param request a message received from client /// - /// @return ACK or NACK message + /// @return ACK or NAK message Pkt4Ptr processRequest(Pkt4Ptr& request); /// @brief Stub function that will handle incoming RELEASE messages. diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes index f43bf09a6f..a3615319a7 100644 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -53,8 +53,8 @@ a received OFFER packet as UNKNOWN). % DHCP6_PACK_FAIL failed to assemble response correctly This error is output if the server failed to assemble the data to be -returned to the client into a valid packet. Additional messages will -detail the reason. +returned to the client into a valid packet. The reason is most likely +to be to a programming error: please raise a bug report. % DHCP6_QUERY_DATA received packet length %1, data length %2, data is <%3> A debug message listing the data received from the client or relay. diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index 3ef57fdb19..1cb323657a 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -72,10 +72,10 @@ public: /// @brief Return textual type of packet received by server /// - /// Returns the name of valid packet received by the server (e.g. DISCOVER). + /// Returns the name of valid packet received by the server (e.g. SOLICIT). /// If the packet is unknown - or if it is a valid DHCP packet but not one - /// expected to be received by the server (such as an OFFER), the string - /// "UNKNOWN" is returned. This methos is used in debug messages. + /// expected to be received by the server (such as an ADVERTISE), the string + /// "UNKNOWN" is returned. This method is used in debug messages. /// /// As the operation of the method does not depend on any server state, it /// is declared static. diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index f1ce8f704b..20287066da 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -268,4 +268,4 @@ TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) { } } -} // anonymous namespace +} // end of anonymous namespace From faf0803218384ff5b61ade0bc13e842dcd384ffd Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Wed, 12 Sep 2012 17:43:20 +0200 Subject: [PATCH 134/148] [2231] Implemented suggestions from code review. --- src/lib/dhcp/iface_mgr.cc | 8 ++-- src/lib/dhcp/tests/iface_mgr_unittest.cc | 52 +++++++++++++----------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 0c99647e27..9570cf5e3a 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -834,7 +834,8 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) { select_timeout.tv_usec = timeout_usec; cout << "Trying to receive data on sockets: " << names.str() - << ". Timeout is " << timeout_sec << " seconds." << endl; + << ". Timeout is " << timeout_sec << "." << setw(6) << setfill('0') + << timeout_usec << " seconds." << endl; int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout); cout << "select returned " << result << endl; @@ -1001,8 +1002,9 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec) { names << session_socket_ << "(session)"; } - cout << "Trying to receive data on sockets:" << names.str() - << ".Timeout is " << timeout_sec << " seconds." << endl; + cout << "Trying to receive data on sockets: " << names.str() + << ". Timeout is " << timeout_sec << "." << setw(6) << setfill('0') + << timeout_usec << " seconds." << endl; struct timeval select_timeout; select_timeout.tv_sec = timeout_sec; diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 3076658a6f..13d471a8e3 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -238,10 +238,12 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { timeval stop_time; // Remember when we call receive6(). + memset(&start_time, 0, sizeof(start_time)); + memset(&stop_time, 0, sizeof(start_time)); gettimeofday(&start_time, NULL); - // Call receive with timeout of 1s + 1000us. + // Call receive with timeout of 1s + 400000us = 1.4s. Pkt6Ptr pkt; - ASSERT_NO_THROW(pkt = ifacemgr->receive6(1, 1000)); + ASSERT_NO_THROW(pkt = ifacemgr->receive6(1, 400000)); // Remember when call to receive6() ended. gettimeofday(&stop_time, NULL); // We did not send a packet to lo interface so we expect that @@ -250,25 +252,26 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { // Calculate duration of call to receive6(). stop_time.tv_sec -= start_time.tv_sec; stop_time.tv_usec -= start_time.tv_usec; - // Duration should be equal or greater than timeout specified + // Duration should be equal or greater or equal timeout specified // for the receive6() call. - EXPECT_EQ(stop_time.tv_sec, 1); - EXPECT_GT(stop_time.tv_usec, 1000); + EXPECT_EQ(1, stop_time.tv_sec); + EXPECT_GE(stop_time.tv_usec, 400000); // Test timeout shorter than 1s. + memset(&start_time, 0, sizeof(start_time)); + memset(&stop_time, 0, sizeof(start_time)); gettimeofday(&start_time, NULL); - ASSERT_NO_THROW(pkt = ifacemgr->receive6(0, 500)); + ASSERT_NO_THROW(pkt = ifacemgr->receive6(0, 500000)); gettimeofday(&stop_time, NULL); ASSERT_FALSE(pkt); stop_time.tv_sec -= start_time.tv_sec; stop_time.tv_usec -= start_time.tv_usec; - // The timeout has been set to 500us. Even though the way we measure - // duration of receive6() may result in durations slightly longer than - // timeout it is safe to assume that measured value will not exceed 1s - // when timeout is only 500us. If it exceeds, this is an error and - // should be investigated. + // Even though the way we measure duration of receive6() may result in + // durations slightly longer than timeout it is safe to assume that + // measured value will not exceed 1s when timeout is 0.5s. + // If it exceeds, this is an error and should be investigated. EXPECT_EQ(0, stop_time.tv_sec); - EXPECT_GT(stop_time.tv_usec, 500); + EXPECT_GE(stop_time.tv_usec, 500000); // Test with invalid fractional timeout values. EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); @@ -296,10 +299,12 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { timeval stop_time; // Remember when we call receive4(). + memset(&start_time, 0, sizeof(start_time)); + memset(&stop_time, 0, sizeof(start_time)); gettimeofday(&start_time, NULL); - // Call receive with timeout of 2s + 150us. + // Call receive with timeout of 2s + 300000us = 2.3s. Pkt4Ptr pkt; - ASSERT_NO_THROW(pkt = ifacemgr->receive4(2, 150)); + ASSERT_NO_THROW(pkt = ifacemgr->receive4(2, 300000)); // Remember when call to receive4() ended. gettimeofday(&stop_time, NULL); // We did not send a packet to lo interface so we expect that @@ -310,23 +315,24 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { stop_time.tv_usec -= start_time.tv_usec; // Duration should be equal or greater than timeout specified // for the receive4() call. - EXPECT_EQ(stop_time.tv_sec, 2); - EXPECT_GT(stop_time.tv_usec, 150); + EXPECT_EQ(2, stop_time.tv_sec); + EXPECT_GE(stop_time.tv_usec, 300000); // Test timeout shorter than 1s. + memset(&start_time, 0, sizeof(start_time)); + memset(&stop_time, 0, sizeof(start_time)); gettimeofday(&start_time, NULL); - ASSERT_NO_THROW(pkt = ifacemgr->receive4(0, 350)); + ASSERT_NO_THROW(pkt = ifacemgr->receive4(0, 400000)); gettimeofday(&stop_time, NULL); ASSERT_FALSE(pkt); stop_time.tv_sec -= start_time.tv_sec; stop_time.tv_usec -= start_time.tv_usec; - // The timeout has been set to 350us. Even though the way we measure - // duration of receive4() may result in durations slightly longer than - // timeout it is safe to assume that measured value will not exceed 1s - // when timeout is only 350us. If it exceeds, this is an error and - // should be investigated. + // Even though the way we measure duration of receive4() may result + // in durations slightly longer than timeout it is safe to assume + // that measured value will not exceed 1s when timeout is only 0.4s. + // If it exceeds, this is an error and should be investigated. EXPECT_EQ(0, stop_time.tv_sec); - EXPECT_GT(stop_time.tv_usec, 350); + EXPECT_GE(stop_time.tv_usec, 400000); // Test with invalid fractional timeout values. EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); From f75dda7a75fdb72cbb5a421669ecc220f5b53944 Mon Sep 17 00:00:00 2001 From: Naoki Kambe Date: Thu, 13 Sep 2012 13:28:59 +0900 Subject: [PATCH 135/148] [master] appended auto-generated doc files into .gitignore. okayed on jabber. --- doc/guide/.gitignore | 3 +++ src/bin/auth/.gitignore | 1 + src/bin/bind10/.gitignore | 1 + src/bin/bindctl/.gitignore | 1 + src/bin/cfgmgr/.gitignore | 1 + src/bin/cmdctl/.gitignore | 1 + src/bin/dbutil/.gitignore | 1 + src/bin/ddns/.gitignore | 1 + src/bin/dhcp4/.gitignore | 1 + src/bin/dhcp6/.gitignore | 1 + src/bin/host/.gitignore | 1 + src/bin/loadzone/.gitignore | 1 + src/bin/msgq/.gitignore | 1 + src/bin/resolver/.gitignore | 1 + src/bin/sockcreator/.gitignore | 1 + src/bin/stats/.gitignore | 2 ++ src/bin/sysinfo/.gitignore | 1 + src/bin/usermgr/.gitignore | 1 + src/bin/xfrin/.gitignore | 1 + src/bin/xfrout/.gitignore | 1 + src/bin/zonemgr/.gitignore | 1 + 21 files changed, 24 insertions(+) create mode 100644 doc/guide/.gitignore diff --git a/doc/guide/.gitignore b/doc/guide/.gitignore new file mode 100644 index 0000000000..168d4ed49e --- /dev/null +++ b/doc/guide/.gitignore @@ -0,0 +1,3 @@ +/bind10-guide.html +/bind10-guide.txt +/bind10-messages.html diff --git a/src/bin/auth/.gitignore b/src/bin/auth/.gitignore index 64c3fd7def..fb06b833f5 100644 --- a/src/bin/auth/.gitignore +++ b/src/bin/auth/.gitignore @@ -5,3 +5,4 @@ /b10-auth /spec_config.h /spec_config.h.pre +/b10-auth.8 diff --git a/src/bin/bind10/.gitignore b/src/bin/bind10/.gitignore index 8dc8a0496b..2cf6b5036f 100644 --- a/src/bin/bind10/.gitignore +++ b/src/bin/bind10/.gitignore @@ -1,3 +1,4 @@ /bind10 /bind10_src.py /run_bind10.sh +/bind10.8 diff --git a/src/bin/bindctl/.gitignore b/src/bin/bindctl/.gitignore index 71fba03ce1..2d4ffbaf28 100644 --- a/src/bin/bindctl/.gitignore +++ b/src/bin/bindctl/.gitignore @@ -1,3 +1,4 @@ /bindctl /bindctl_main.py /run_bindctl.sh +/bindctl.1 diff --git a/src/bin/cfgmgr/.gitignore b/src/bin/cfgmgr/.gitignore index aad54f4055..1ef37efd9f 100644 --- a/src/bin/cfgmgr/.gitignore +++ b/src/bin/cfgmgr/.gitignore @@ -1,2 +1,3 @@ /b10-cfgmgr /b10-cfgmgr.py +/b10-cfgmgr.8 diff --git a/src/bin/cmdctl/.gitignore b/src/bin/cmdctl/.gitignore index a194135a22..01e3ef054e 100644 --- a/src/bin/cmdctl/.gitignore +++ b/src/bin/cmdctl/.gitignore @@ -3,3 +3,4 @@ /cmdctl.spec /cmdctl.spec.pre /run_b10-cmdctl.sh +/b10-cmdctl.8 diff --git a/src/bin/dbutil/.gitignore b/src/bin/dbutil/.gitignore index abb63d54eb..6348236930 100644 --- a/src/bin/dbutil/.gitignore +++ b/src/bin/dbutil/.gitignore @@ -1,3 +1,4 @@ /b10-dbutil /dbutil.py /run_dbutil.sh +/b10-dbutil.8 diff --git a/src/bin/ddns/.gitignore b/src/bin/ddns/.gitignore index 92b86f3098..fff8c5f311 100644 --- a/src/bin/ddns/.gitignore +++ b/src/bin/ddns/.gitignore @@ -1,2 +1,3 @@ /b10-ddns /ddns.py +/b10-ddns.8 diff --git a/src/bin/dhcp4/.gitignore b/src/bin/dhcp4/.gitignore index f7e9973b9f..952db06e0e 100644 --- a/src/bin/dhcp4/.gitignore +++ b/src/bin/dhcp4/.gitignore @@ -1,3 +1,4 @@ /b10-dhcp4 /spec_config.h /spec_config.h.pre +/b10-dhcp4.8 diff --git a/src/bin/dhcp6/.gitignore b/src/bin/dhcp6/.gitignore index e4e8f2df6a..eedbb846cb 100644 --- a/src/bin/dhcp6/.gitignore +++ b/src/bin/dhcp6/.gitignore @@ -8,3 +8,4 @@ b10-dhcp6 spec_config.h spec_config.h.pre tests/dhcp6_unittests +/b10-dhcp6.8 diff --git a/src/bin/host/.gitignore b/src/bin/host/.gitignore index 0073523b39..01ef357a26 100644 --- a/src/bin/host/.gitignore +++ b/src/bin/host/.gitignore @@ -1 +1,2 @@ /b10-host +/b10-host.1 diff --git a/src/bin/loadzone/.gitignore b/src/bin/loadzone/.gitignore index 86761ee814..59f0bb58e1 100644 --- a/src/bin/loadzone/.gitignore +++ b/src/bin/loadzone/.gitignore @@ -1,3 +1,4 @@ /b10-loadzone /b10-loadzone.py /run_loadzone.sh +/b10-loadzone.8 diff --git a/src/bin/msgq/.gitignore b/src/bin/msgq/.gitignore index ee1d94228d..ecd1bad2cb 100644 --- a/src/bin/msgq/.gitignore +++ b/src/bin/msgq/.gitignore @@ -1,3 +1,4 @@ /b10-msgq /msgq.py /run_msgq.sh +/b10-msgq.8 diff --git a/src/bin/resolver/.gitignore b/src/bin/resolver/.gitignore index 95abd500c2..b3abbc9b7c 100644 --- a/src/bin/resolver/.gitignore +++ b/src/bin/resolver/.gitignore @@ -5,3 +5,4 @@ /resolver_messages.h /spec_config.h /spec_config.h.pre +/b10-resolver.8 diff --git a/src/bin/sockcreator/.gitignore b/src/bin/sockcreator/.gitignore index 29851849cd..6d9d0514dd 100644 --- a/src/bin/sockcreator/.gitignore +++ b/src/bin/sockcreator/.gitignore @@ -1 +1,2 @@ /b10-sockcreator +/b10-sockcreator.8 diff --git a/src/bin/stats/.gitignore b/src/bin/stats/.gitignore index 7ff3797fde..8dacd7e47a 100644 --- a/src/bin/stats/.gitignore +++ b/src/bin/stats/.gitignore @@ -2,3 +2,5 @@ /b10-stats-httpd /stats.py /stats_httpd.py +/b10-stats-httpd.8 +/b10-stats.8 diff --git a/src/bin/sysinfo/.gitignore b/src/bin/sysinfo/.gitignore index 7a91274249..9194aff8ec 100644 --- a/src/bin/sysinfo/.gitignore +++ b/src/bin/sysinfo/.gitignore @@ -1,2 +1,3 @@ /isc-sysinfo /sysinfo.py +/isc-sysinfo.1 diff --git a/src/bin/usermgr/.gitignore b/src/bin/usermgr/.gitignore index e116052663..36e32a09be 100644 --- a/src/bin/usermgr/.gitignore +++ b/src/bin/usermgr/.gitignore @@ -1,3 +1,4 @@ /b10-cmdctl-usermgr /b10-cmdctl-usermgr.py /run_b10-cmdctl-usermgr.sh +/b10-cmdctl-usermgr.8 diff --git a/src/bin/xfrin/.gitignore b/src/bin/xfrin/.gitignore index 5ac19425e2..a1c78ccdf3 100644 --- a/src/bin/xfrin/.gitignore +++ b/src/bin/xfrin/.gitignore @@ -1,3 +1,4 @@ /b10-xfrin /run_b10-xfrin.sh /xfrin.py +/b10-xfrin.8 diff --git a/src/bin/xfrout/.gitignore b/src/bin/xfrout/.gitignore index 2ace679bb6..d2a69f30db 100644 --- a/src/bin/xfrout/.gitignore +++ b/src/bin/xfrout/.gitignore @@ -3,3 +3,4 @@ /xfrout.py /xfrout.spec /xfrout.spec.pre +/b10-xfrout.8 diff --git a/src/bin/zonemgr/.gitignore b/src/bin/zonemgr/.gitignore index 2d64f2d6c1..815de93445 100644 --- a/src/bin/zonemgr/.gitignore +++ b/src/bin/zonemgr/.gitignore @@ -3,3 +3,4 @@ /zonemgr.py /zonemgr.spec /zonemgr.spec.pre +/b10-zonemgr.8 From 362a944a677040f1b0aa08dcd1d7e43359557ea1 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 13 Sep 2012 07:23:26 +0200 Subject: [PATCH 136/148] [master] Clean template files produced by perfdhcp unit test. Discussed with jreed on jabber. --- tests/tools/perfdhcp/templates/Makefile.am | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/tools/perfdhcp/templates/Makefile.am b/tests/tools/perfdhcp/templates/Makefile.am index 4da2027903..1eee19c937 100644 --- a/tests/tools/perfdhcp/templates/Makefile.am +++ b/tests/tools/perfdhcp/templates/Makefile.am @@ -1,8 +1,12 @@ SUBDIRS = . +# The test1.hex and test2.hex are created by the TestControl.PacketTemplates +# unit tests and have to be removed. +CLEANFILES = test1.hex test2.hex + perfdhcpdir = $(pkgdatadir) -perfdhcp_DATA = discover-example.hex request4-example.hex \ - solicit-example.hex request6-example.hex +perfdhcp_DATA = discover-example.hex request4-example.hex +perfdhcp_DATA += solicit-example.hex request6-example.hex EXTRA_DIST = discover-example.hex request4-example.hex EXTRA_DIST += solicit-example.hex request6-example.hex From 53e77f34ca655fc29320bba05a12a98355c365fb Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 13 Sep 2012 09:10:30 +0200 Subject: [PATCH 137/148] [2231] Simplify the duration measurements with boost::posix_time. --- src/lib/dhcp/tests/iface_mgr_unittest.cc | 92 +++++++++++------------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 13d471a8e3..adcba3152a 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -218,6 +218,7 @@ TEST_F(IfaceMgrTest, getIface) { } TEST_F(IfaceMgrTest, receiveTimeout6) { + using namespace boost::posix_time; std::cout << "Testing DHCPv6 packet reception timeouts." << " Test will block for a few seconds when waiting" << " for timeout to occur." << std::endl; @@ -233,45 +234,40 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { ASSERT_GT(socket1, 0); // Time when call to IfaceMgr::receive6() started. - timeval start_time; + ptime start_time; // Time when call to IfaceMgr::receive6() ended. - timeval stop_time; + ptime stop_time; + // Time duration between start_time and stop_time. + time_duration duration; // Remember when we call receive6(). - memset(&start_time, 0, sizeof(start_time)); - memset(&stop_time, 0, sizeof(start_time)); - gettimeofday(&start_time, NULL); + start_time = microsec_clock::universal_time(); // Call receive with timeout of 1s + 400000us = 1.4s. Pkt6Ptr pkt; ASSERT_NO_THROW(pkt = ifacemgr->receive6(1, 400000)); // Remember when call to receive6() ended. - gettimeofday(&stop_time, NULL); + stop_time = microsec_clock::universal_time(); // We did not send a packet to lo interface so we expect that // nothing has been received and timeout has been reached. ASSERT_FALSE(pkt); // Calculate duration of call to receive6(). - stop_time.tv_sec -= start_time.tv_sec; - stop_time.tv_usec -= start_time.tv_usec; - // Duration should be equal or greater or equal timeout specified - // for the receive6() call. - EXPECT_EQ(1, stop_time.tv_sec); - EXPECT_GE(stop_time.tv_usec, 400000); + duration = stop_time - start_time; + // We stop the clock when the call completes so it does not + // precisely reflect the receive timeout. However the + // uncertainity should be low enough to expect that measured + // value is in the range <1.4; 2). + EXPECT_GE(duration.total_microseconds(), 1400000); + EXPECT_LT(duration.total_seconds(), 2); // Test timeout shorter than 1s. - memset(&start_time, 0, sizeof(start_time)); - memset(&stop_time, 0, sizeof(start_time)); - gettimeofday(&start_time, NULL); + start_time = microsec_clock::universal_time(); ASSERT_NO_THROW(pkt = ifacemgr->receive6(0, 500000)); - gettimeofday(&stop_time, NULL); + stop_time = microsec_clock::universal_time(); ASSERT_FALSE(pkt); - stop_time.tv_sec -= start_time.tv_sec; - stop_time.tv_usec -= start_time.tv_usec; - // Even though the way we measure duration of receive6() may result in - // durations slightly longer than timeout it is safe to assume that - // measured value will not exceed 1s when timeout is 0.5s. - // If it exceeds, this is an error and should be investigated. - EXPECT_EQ(0, stop_time.tv_sec); - EXPECT_GE(stop_time.tv_usec, 500000); + duration = stop_time - start_time; + // Check if measured duration is within <0.5s; 1s). + EXPECT_GE(duration.total_microseconds(), 500000); + EXPECT_LT(duration.total_seconds(), 1); // Test with invalid fractional timeout values. EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); @@ -279,6 +275,7 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { } TEST_F(IfaceMgrTest, receiveTimeout4) { + using namespace boost::posix_time; std::cout << "Testing DHCPv6 packet reception timeouts." << " Test will block for a few seconds when waiting" << " for timeout to occur." << std::endl; @@ -294,45 +291,40 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { ASSERT_GT(socket1, 0); // Time when call to IfaceMgr::receive4() started. - timeval start_time; + ptime start_time; // Time when call to IfaceMgr::receive4() ended. - timeval stop_time; + ptime stop_time; + // Time duration between start_time and stop_time. + time_duration duration; - // Remember when we call receive4(). - memset(&start_time, 0, sizeof(start_time)); - memset(&stop_time, 0, sizeof(start_time)); - gettimeofday(&start_time, NULL); - // Call receive with timeout of 2s + 300000us = 2.3s. Pkt4Ptr pkt; + // Remember when we call receive4(). + start_time = microsec_clock::universal_time(); + // Call receive with timeout of 2s + 300000us = 2.3s. ASSERT_NO_THROW(pkt = ifacemgr->receive4(2, 300000)); // Remember when call to receive4() ended. - gettimeofday(&stop_time, NULL); + stop_time = microsec_clock::universal_time(); // We did not send a packet to lo interface so we expect that // nothing has been received and timeout has been reached. ASSERT_FALSE(pkt); // Calculate duration of call to receive4(). - stop_time.tv_sec -= start_time.tv_sec; - stop_time.tv_usec -= start_time.tv_usec; - // Duration should be equal or greater than timeout specified - // for the receive4() call. - EXPECT_EQ(2, stop_time.tv_sec); - EXPECT_GE(stop_time.tv_usec, 300000); + duration = stop_time - start_time; + // We stop the clock when the call completes so it does not + // precisely reflect the receive timeout. However the + // uncertainity should be low enough to expect that measured + // value is in the range <2.3s; 3s). + EXPECT_GE(duration.total_microseconds(), 2300000); + EXPECT_LT(duration.total_seconds(), 3); // Test timeout shorter than 1s. - memset(&start_time, 0, sizeof(start_time)); - memset(&stop_time, 0, sizeof(start_time)); - gettimeofday(&start_time, NULL); + start_time = microsec_clock::universal_time(); ASSERT_NO_THROW(pkt = ifacemgr->receive4(0, 400000)); - gettimeofday(&stop_time, NULL); + stop_time = microsec_clock::universal_time(); ASSERT_FALSE(pkt); - stop_time.tv_sec -= start_time.tv_sec; - stop_time.tv_usec -= start_time.tv_usec; - // Even though the way we measure duration of receive4() may result - // in durations slightly longer than timeout it is safe to assume - // that measured value will not exceed 1s when timeout is only 0.4s. - // If it exceeds, this is an error and should be investigated. - EXPECT_EQ(0, stop_time.tv_sec); - EXPECT_GE(stop_time.tv_usec, 400000); + duration = stop_time - start_time; + // Check if measured duration is within <0.4s; 1s). + EXPECT_GE(duration.total_microseconds(), 400000); + EXPECT_LT(duration.total_seconds(), 1); // Test with invalid fractional timeout values. EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); From 250da3f615ed6d09380dc2de7e6633017530bffd Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 13 Sep 2012 09:37:37 +0200 Subject: [PATCH 138/148] [2231] Show default timeout_usec values in implementation. --- src/lib/dhcp/iface_mgr.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 9570cf5e3a..9a082d2d87 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -785,7 +785,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt) boost::shared_ptr -IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) { +IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) { // Sanity check for microsecond timeout. if (timeout_usec >= 1000000) { isc_throw(BadValue, "fractional timeout must be shorter than" @@ -957,7 +957,7 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) { return (pkt); } -Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec) { +Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ ) { // Sanity check for microsecond timeout. if (timeout_usec >= 1000000) { isc_throw(BadValue, "fractional timeout must be shorter than" From fc5c1f86c0af76912daa4a22d3dc6bece80726e4 Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Thu, 13 Sep 2012 15:20:29 +0530 Subject: [PATCH 139/148] [master] Handle default switch case in LoggerImpl::outputRaw() --- src/lib/log/logger_impl.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc index 6cd3da532e..689795d537 100644 --- a/src/lib/log/logger_impl.cc +++ b/src/lib/log/logger_impl.cc @@ -151,6 +151,15 @@ LoggerImpl::outputRaw(const Severity& severity, const string& message) { case FATAL: LOG4CPLUS_FATAL(logger_, message); + break; + + case NONE: + break; + + default: + LOG4CPLUS_ERROR(logger_, + "Unsupported severity in LoggerImpl::outputRaw(): " + << severity); } if (!locker.unlock()) { From 6a119e4ae98b2126f8f32ba4ad69ba98bd8a3144 Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Thu, 13 Sep 2012 09:39:39 +0530 Subject: [PATCH 140/148] [master] Remove some unused assignments Reported by clang-analyzer. --- src/lib/log/tests/logger_example.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/log/tests/logger_example.cc b/src/lib/log/tests/logger_example.cc index 853d48a73f..6f95e5d1a3 100644 --- a/src/lib/log/tests/logger_example.cc +++ b/src/lib/log/tests/logger_example.cc @@ -146,7 +146,7 @@ int main(int argc, char** argv) { if (c_found || f_found || y_found) { cur_spec.addOutputOption(cur_opt); cur_opt = def_opt; - c_found = f_found = y_found = false; + f_found = y_found = false; } // Set the output option for this switch. @@ -174,7 +174,7 @@ int main(int argc, char** argv) { if (c_found || f_found || y_found) { cur_spec.addOutputOption(cur_opt); cur_opt = def_opt; - c_found = f_found = y_found = false; + c_found = y_found = false; } // Set the output option for this switch. @@ -236,7 +236,7 @@ int main(int argc, char** argv) { if (c_found || f_found || y_found) { cur_spec.addOutputOption(cur_opt); cur_opt = def_opt; - c_found = f_found = y_found = false; + c_found = f_found = false; } y_found = true; cur_opt.destination = OutputOption::DEST_SYSLOG; From ccdbcf02d9f4a2bbd69475428b86458c1ee6334a Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Thu, 13 Sep 2012 15:22:22 +0530 Subject: [PATCH 141/148] [master] Remove redundant NULL checks in PySerial These are not required according to: http://docs.python.org/py3k/extending/extending.html?highlight=null#null-pointers These NULL checks cause static analysis reports in other parts of the code where the pointers are not NULL tested before use. --- src/lib/dns/python/serial_python.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/lib/dns/python/serial_python.cc b/src/lib/dns/python/serial_python.cc index e2bd809219..f4f4720df5 100644 --- a/src/lib/dns/python/serial_python.cc +++ b/src/lib/dns/python/serial_python.cc @@ -259,19 +259,11 @@ createSerialObject(const Serial& source) { bool PySerial_Check(PyObject* obj) { - if (obj == NULL) { - isc_throw(PyCPPWrapperException, - "obj argument NULL in Serial typecheck"); - } return (PyObject_TypeCheck(obj, &serial_type)); } const Serial& PySerial_ToSerial(const PyObject* serial_obj) { - if (serial_obj == NULL) { - isc_throw(PyCPPWrapperException, - "obj argument NULL in Serial PyObject conversion"); - } const s_Serial* serial = static_cast(serial_obj); return (*serial->cppobj); } From e15c888265457e74ee5977659d6588a2d7a0d0e2 Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Thu, 13 Sep 2012 10:02:23 +0530 Subject: [PATCH 142/148] [master] Add assertion to test that cmsg != NULL The assert() should silence clang-analyer. --- src/lib/dhcp/iface_mgr.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 7df809e776..7f1b38ba8b 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -727,6 +727,13 @@ IfaceMgr::send(const Pkt6Ptr& pkt) { m.msg_control = &control_buf_[0]; m.msg_controllen = control_buf_len_; struct cmsghdr *cmsg = CMSG_FIRSTHDR(&m); + + // FIXME: Code below assumes that cmsg is not NULL, but + // CMSG_FIRSTHDR() is coded to return NULL as a possibility. The + // following assertion should never fail, but if it did and you came + // here, fix the code. :) + assert(cmsg != NULL); + cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); From aea6e2d1a3e08c8239323dc076cdd9cc2620b09c Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Thu, 13 Sep 2012 10:03:58 +0530 Subject: [PATCH 143/148] [master] Assign rcode Strictly, this is done to silence clang-analyzer. In every case, parseAnswer() does set rcode (which is passed by reference) unless it throws. It looks like clang-analyzer gets confused by the exception paths. In any case, it's good to initialize it to the unexpected case and not depend on parseAnswer(). --- src/lib/config/ccsession.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc index d4c6653b6c..daec005dda 100644 --- a/src/lib/config/ccsession.cc +++ b/src/lib/config/ccsession.cc @@ -456,7 +456,7 @@ ModuleCCSession::ModuleCCSession( ConstElementPtr answer, env; session_.group_recvmsg(env, answer, false, seq); - int rcode; + int rcode = -1; ConstElementPtr err = parseAnswer(rcode, answer); if (rcode != 0) { LOG_ERROR(config_logger, CONFIG_MOD_SPEC_REJECT).arg(answer->str()); @@ -535,7 +535,7 @@ ModuleCCSession::handleConfigUpdate(ConstElementPtr new_config) { ConstElementPtr diff = removeIdentical(new_config, getLocalConfig()); // handle config update answer = config_handler_(diff); - int rcode; + int rcode = -1; parseAnswer(rcode, answer); if (rcode == 0) { ElementPtr local_config = getLocalConfig(); @@ -652,7 +652,7 @@ ModuleCCSession::fetchRemoteSpec(const std::string& module, bool is_filename) { unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager"); ConstElementPtr env, answer; session_.group_recvmsg(env, answer, false, seq); - int rcode; + int rcode = -1; ConstElementPtr spec_data = parseAnswer(rcode, answer); if (rcode == 0 && spec_data) { // received OK, construct the spec out of it @@ -689,7 +689,7 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_name, ConstElementPtr env, answer; session_.group_recvmsg(env, answer, false, seq); - int rcode; + int rcode = -1; ConstElementPtr new_config = parseAnswer(rcode, answer); ElementPtr local_config; if (rcode == 0 && new_config) { From b7598c1bf13043ba397c898849567ada04bbee9b Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 13 Sep 2012 14:25:42 +0200 Subject: [PATCH 144/148] [2231] Corrected validation ranges for timeouts. --- src/lib/dhcp/tests/iface_mgr_unittest.cc | 42 ++++++++---------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index adcba3152a..02dca323d9 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -233,31 +233,24 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { // Socket is open if its descriptor is greater than zero. ASSERT_GT(socket1, 0); - // Time when call to IfaceMgr::receive6() started. - ptime start_time; - // Time when call to IfaceMgr::receive6() ended. - ptime stop_time; - // Time duration between start_time and stop_time. - time_duration duration; - // Remember when we call receive6(). - start_time = microsec_clock::universal_time(); + ptime start_time = microsec_clock::universal_time(); // Call receive with timeout of 1s + 400000us = 1.4s. Pkt6Ptr pkt; ASSERT_NO_THROW(pkt = ifacemgr->receive6(1, 400000)); // Remember when call to receive6() ended. - stop_time = microsec_clock::universal_time(); + ptime stop_time = microsec_clock::universal_time(); // We did not send a packet to lo interface so we expect that // nothing has been received and timeout has been reached. ASSERT_FALSE(pkt); // Calculate duration of call to receive6(). - duration = stop_time - start_time; + time_duration duration = stop_time - start_time; // We stop the clock when the call completes so it does not // precisely reflect the receive timeout. However the // uncertainity should be low enough to expect that measured - // value is in the range <1.4; 2). + // value is in the range <1.4s; 1.7s>. EXPECT_GE(duration.total_microseconds(), 1400000); - EXPECT_LT(duration.total_seconds(), 2); + EXPECT_LE(duration.total_microseconds(), 1700000); // Test timeout shorter than 1s. start_time = microsec_clock::universal_time(); @@ -265,9 +258,9 @@ TEST_F(IfaceMgrTest, receiveTimeout6) { stop_time = microsec_clock::universal_time(); ASSERT_FALSE(pkt); duration = stop_time - start_time; - // Check if measured duration is within <0.5s; 1s). + // Check if measured duration is within <0.5s; 0.8s>. EXPECT_GE(duration.total_microseconds(), 500000); - EXPECT_LT(duration.total_seconds(), 1); + EXPECT_LE(duration.total_microseconds(), 800000); // Test with invalid fractional timeout values. EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); @@ -290,31 +283,24 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { // Socket is open if its descriptor is greater than zero. ASSERT_GT(socket1, 0); - // Time when call to IfaceMgr::receive4() started. - ptime start_time; - // Time when call to IfaceMgr::receive4() ended. - ptime stop_time; - // Time duration between start_time and stop_time. - time_duration duration; - Pkt4Ptr pkt; // Remember when we call receive4(). - start_time = microsec_clock::universal_time(); + ptime start_time = microsec_clock::universal_time(); // Call receive with timeout of 2s + 300000us = 2.3s. ASSERT_NO_THROW(pkt = ifacemgr->receive4(2, 300000)); // Remember when call to receive4() ended. - stop_time = microsec_clock::universal_time(); + ptime stop_time = microsec_clock::universal_time(); // We did not send a packet to lo interface so we expect that // nothing has been received and timeout has been reached. ASSERT_FALSE(pkt); // Calculate duration of call to receive4(). - duration = stop_time - start_time; + time_duration duration = stop_time - start_time; // We stop the clock when the call completes so it does not // precisely reflect the receive timeout. However the // uncertainity should be low enough to expect that measured - // value is in the range <2.3s; 3s). + // value is in the range <2.3s; 2.6s>. EXPECT_GE(duration.total_microseconds(), 2300000); - EXPECT_LT(duration.total_seconds(), 3); + EXPECT_LE(duration.total_microseconds(), 2600000); // Test timeout shorter than 1s. start_time = microsec_clock::universal_time(); @@ -322,9 +308,9 @@ TEST_F(IfaceMgrTest, receiveTimeout4) { stop_time = microsec_clock::universal_time(); ASSERT_FALSE(pkt); duration = stop_time - start_time; - // Check if measured duration is within <0.4s; 1s). + // Check if measured duration is within <0.4s; 0.7s>. EXPECT_GE(duration.total_microseconds(), 400000); - EXPECT_LT(duration.total_seconds(), 1); + EXPECT_LE(duration.total_microseconds(), 700000); // Test with invalid fractional timeout values. EXPECT_THROW(ifacemgr->receive6(0, 1000000), isc::BadValue); From 8ad1accced4284ff727b03c43cab755566e486ab Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 14 Sep 2012 10:10:15 +0200 Subject: [PATCH 145/148] [master] Use CommandOptionsHelper for CommandOptions unit tests. This fixes memory leak reported by Valgrind. Dicussed with Jelte on jabber. --- .../tests/command_options_unittest.cc | 49 +------------------ 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/tests/tools/perfdhcp/tests/command_options_unittest.cc b/tests/tools/perfdhcp/tests/command_options_unittest.cc index 0481d28da3..801b02dd29 100644 --- a/tests/tools/perfdhcp/tests/command_options_unittest.cc +++ b/tests/tools/perfdhcp/tests/command_options_unittest.cc @@ -21,7 +21,7 @@ #include #include -#include "../command_options.h" +#include "command_options_helper.h" using namespace std; using namespace isc; @@ -48,16 +48,7 @@ protected: /// \param cmdline Command line to parse /// \throws std::bad allocation if tokenization failed void process(const std::string& cmdline) { - CommandOptions& opt = CommandOptions::instance(); - int argc = 0; - char** argv = tokenizeString(cmdline, &argc); - opt.reset(); - opt.parse(argc, argv); - for(int i = 0; i < argc; ++i) { - free(argv[i]); - argv[i] = NULL; - } - free(argv); + CommandOptionsHelper::process(cmdline); } /// \brief Check default initialized values @@ -143,42 +134,6 @@ protected: EXPECT_EQ("", opt.getWrapped()); EXPECT_EQ("192.168.0.1", opt.getServerName()); } - - /// \brief Split string to array of C-strings - /// - /// \param s String to split (tokenize) - /// \param num Number of tokens returned - /// \return array of C-strings (tokens) - char** tokenizeString(const std::string& text_to_split, int* num) const { - char** results = NULL; - // Tokenization with std streams - std::stringstream text_stream(text_to_split); - // Iterators to be used for tokenization - std::istream_iterator text_iterator(text_stream); - std::istream_iterator text_end; - // Tokenize string (space is a separator) using begin and end iteratos - std::vector tokens(text_iterator, text_end); - - if (tokens.size() > 0) { - // Allocate array of C-strings where we will store tokens - results = static_cast(malloc(tokens.size() * sizeof(char*))); - if (results == NULL) { - throw std::bad_alloc(); - } - // Store tokens in C-strings array - for (int i = 0; i < tokens.size(); ++i) { - char* cs = static_cast(malloc(tokens[i].length() + 1)); - strcpy(cs, tokens[i].c_str()); - results[i] = cs; - } - // Return number of tokens to calling function - if (num != NULL) { - *num = tokens.size(); - } - } - return results; - } - }; TEST_F(CommandOptionsTest, Defaults) { From d6f3e1aa02ffc1de9d55a586174022eb60f43887 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Fri, 14 Sep 2012 15:16:56 +0100 Subject: [PATCH 146/148] [1545] Corrected problems in setting environment variable in tests For some reason, the Python "os.putenv()" did not work, so changed to morifying the "os.environ" variable directly. --- src/bin/dhcp4/tests/dhcp4_test.py | 8 ++++---- src/bin/dhcp6/tests/dhcp6_test.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bin/dhcp4/tests/dhcp4_test.py b/src/bin/dhcp4/tests/dhcp4_test.py index 3ad97c6c98..efe16fb7a9 100644 --- a/src/bin/dhcp4/tests/dhcp4_test.py +++ b/src/bin/dhcp4/tests/dhcp4_test.py @@ -32,11 +32,11 @@ class TestDhcpv4Daemon(unittest.TestCase): # # However, we do want to set the logging lock directory to somewhere # to which we can write - use the current working directory. We then - # set the appropriate environment variable. + # set the appropriate environment variable. os.putenv() doesn't work + # on Ubuntu, so we access os.environ directly. lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD" - lockdir = os.getenv(lockdir_envvar) - if lockdir is None: - os.putenv(lockdir_envvar, os.getcwd()) + if lockdir_envvar not in os.environ: + os.environ[lockdir_envvar] = os.getcwd() def tearDown(self): pass diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py index 0887bbf2a0..78202bd910 100644 --- a/src/bin/dhcp6/tests/dhcp6_test.py +++ b/src/bin/dhcp6/tests/dhcp6_test.py @@ -32,11 +32,11 @@ class TestDhcpv6Daemon(unittest.TestCase): # # However, we do want to set the logging lock directory to somewhere # to which we can write - use the current working directory. We then - # set the appropriate environment variable. + # set the appropriate environment variable. os.putenv() doesn't work + # on Ubuntu, so we access os.environ directly. lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD" - lockdir = os.getenv(lockdir_envvar) - if lockdir is None: - os.putenv(lockdir_envvar, os.getcwd()) + if lockdir_envvar not in os.environ: + os.environ[lockdir_envvar] = os.getcwd() def tearDown(self): pass From 38c6a4866e5be6f6a7ed3497f0fef252583b5be4 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Fri, 14 Sep 2012 19:14:34 +0200 Subject: [PATCH 147/148] [1545] Added reference to python documentation for os.putenv() function. The os.putenv() functionsseems to be not supported on all platforms and this is indicated in the python documentation. --- src/bin/dhcp4/tests/dhcp4_test.py | 8 ++++++-- src/bin/dhcp6/tests/dhcp6_test.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/bin/dhcp4/tests/dhcp4_test.py b/src/bin/dhcp4/tests/dhcp4_test.py index efe16fb7a9..444dfcfd2a 100644 --- a/src/bin/dhcp4/tests/dhcp4_test.py +++ b/src/bin/dhcp4/tests/dhcp4_test.py @@ -32,8 +32,12 @@ class TestDhcpv4Daemon(unittest.TestCase): # # However, we do want to set the logging lock directory to somewhere # to which we can write - use the current working directory. We then - # set the appropriate environment variable. os.putenv() doesn't work - # on Ubuntu, so we access os.environ directly. + # set the appropriate environment variable. os.putenv() may be not + # supported on some platforms as suggested in + # http://docs.python.org/release/3.2/library/os.html?highlight=putenv#os.environ: + # "If the platform supports the putenv() function...". It was checked + # that it does not work on Ubuntu. To overcome this problem we access + # os.environ directly. lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD" if lockdir_envvar not in os.environ: os.environ[lockdir_envvar] = os.getcwd() diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py index 78202bd910..f3099b9a83 100644 --- a/src/bin/dhcp6/tests/dhcp6_test.py +++ b/src/bin/dhcp6/tests/dhcp6_test.py @@ -32,8 +32,12 @@ class TestDhcpv6Daemon(unittest.TestCase): # # However, we do want to set the logging lock directory to somewhere # to which we can write - use the current working directory. We then - # set the appropriate environment variable. os.putenv() doesn't work - # on Ubuntu, so we access os.environ directly. + # set the appropriate environment variable. os.putenv() may be not + # supported on some platforms as suggested in + # http://docs.python.org/release/3.2/library/os.html?highlight=putenv#os.environ: + # "If the platform supports the putenv() function...". It was checked + # that it does not work on Ubuntu. To overcome this problem we access + # os.environ directly. lockdir_envvar = "B10_LOCKFILE_DIR_FROM_BUILD" if lockdir_envvar not in os.environ: os.environ[lockdir_envvar] = os.getcwd() From 68ebb92883a7cd9bb84b3b39cab2049b59119e36 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Mon, 17 Sep 2012 11:54:07 +0100 Subject: [PATCH 148/148] [master] ChangeLog entry for ticket 1545. --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index da4a82666a..dfcfa606f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +474. [func] stephen + DHCP servers now use the BIND 10 logging system for messages. + (Trac #1545, git de69a92613b36bd3944cb061e1b7c611c3c85506) + 473. [bug] jelte TCP connections now time out in b10-auth if no (or not all) query data is sent by the client. The timeout value defaults to 5000