Commit f62ca4a0 authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[master] Added ChangeLog entry 623 for trac 2955.

parents 36f8c6c1 36cb12b0
622. [func] tmark
623. [func] tmark
Created the initial, bare-bones implementation of DHCP-DDNS service
process class, D2Process, and the abstract class from which it derives,
DProcessBase. D2Process will provide the DHCP-DDNS specific event loop
and business logic.
(Trac #2955, git dbe4772246039a1257b6492936fda2a8600cd245)
622. [func]* jinmei
b10-xfrin now has tighter control on the choice of IXFR or AXFR
through zones/request_ixfr configuration item. It includes
the new "IXFR only" behavior for some special cases. b10-xfrin
now also uses AXFR whenever necessary, so it is now safe to try
IXFR by default and it's made the default. The previous
use_ixfr configuration item was deprecated and triggers startup
failure if specified; configuration using use_ixfr should be
updated.
(Trac #2911, git 8118f8e4e9c0ad3e7b690bbce265a163e4f8767a)
621. [func] team
libdns++: All Rdata classes now use the generic lexer in
constructors from text. This means that the name fields in such
......
......@@ -2725,11 +2725,8 @@ TODO
<para>
The <command>b10-xfrin</command> 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.
IXFR.
</para>
<!-- TODO: http://bind10.isc.org/ticket/1279 -->
<section>
<title>Configuration for Incoming Zone Transfers</title>
......@@ -2763,34 +2760,82 @@ TODO
&gt; <userinput>config set Xfrin/zones[0]/tsig_key "<option>example.key</option>"</userinput>
</section>
<section>
<title>Enabling IXFR</title>
<para>
As noted above, <command>b10-xfrin</command> uses AXFR for
zone transfers by default. To enable IXFR for zone transfers
for a particular zone, set the <varname>use_ixfr</varname>
configuration parameter to <quote>true</quote>.
In the above example of configuration sequence, you'll need
to add the following before performing <userinput>commit</userinput>:
<screen>&gt; <userinput>config set Xfrin/zones[0]/use_ixfr true</userinput></screen>
</para>
<section id="request_ixfr">
<title>Control the use of IXFR</title>
<para>
By default, <command>b10-xfrin</command> uses IXFR for
transferring zones specified in
the <varname>Xfrin/zones</varname> list of the configuration,
unless it doesn't know the current SOA serial of the zone
(including the case where the zone has never transferred or
locally loaded), in which case it automatically uses AXFR.
If the attempt of IXFR fails, <command>b10-xfrin</command>
automatically retries the transfer using AXFR.
In general, this works for any master server implementations
including those that don't support IXFR and in any local state
of the zone. So there should normally be no need to configure
on whether to use IXFR.
</para>
<para>
In some cases, however, it may be desirable to specify how and
whether to use IXFR and AXFR.
The <varname>request_ixfr</varname> configuration item under
<varname>Xfrin/zones</varname> can be used to control such
policies.
It can take the following values.
</para>
<variablelist>
<varlistentry>
<term>yes</term>
<listitem>
<simpara>
This is the default behavior as described above.
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>no</term>
<listitem>
<simpara>
Only use AXFR. Note that this value normally shouldn't
be needed thanks to the automatic fallback from IXFR to IXFR.
A possible case where this value needs to be used is
that the master server has a bug and crashes if it
receives an IXFR request.
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>only</term>
<listitem>
<simpara>
Only use IXFR except when the current SOA serial is not
known.
This value has a severe drawback, that is, if the master
server does not support IXFR zone transfers never
succeed (except for the very first one, which will use AXFR),
and the zone will eventually expire.
Therefore it should not be used in general.
Still, in some special cases the use of this value may
make sense. For example, if the operator is sure that
the master server supports IXFR and the zone is very
large, they may want to avoid falling back to AXFR as
it can be more expensive.
</simpara>
</listitem>
</varlistentry>
</variablelist>
<note>
<simpara>
There used to be a boolean configuration item named
<varname>use_ixfr</varname>.
It was deprecated for the finer control described above.
The <varname>request_ixfr</varname> item should be used instead.
</simpara>
</note>
<!-- TODO: http://bind10.isc.org/ticket/1279 -->
<note><simpara>
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 <command>b10-xfrin</command> 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.
</simpara></note>
</section>
<!-- TODO:
......@@ -2854,6 +2899,23 @@ what if a NOTIFY is sent?
<screen>&gt; <userinput>Xfrin retransfer zone_name="<option>foo.example.org</option>" master=<option>192.0.2.99</option></userinput></screen>
</para>
<para>
The <command>retransfer</command> command always uses AXFR.
To use IXFR for a zone that has already been transferred once,
use the <command>refresh</command> command.
It honors the <varname>Xfrin/zones/request_ixfr</varname>
configuration item (see <xref linkend="request_ixfr"/>.), and
if it's configured to use IXFR, it will be used.
</para>
<para>
Both the <command>retransfer</command>
and <command>refresh</command> commands can be used for
an initial transfer before setting up secondary
configurations.
In this case AXFR will be used for the obvious reason.
</para>
</section>
<section>
......@@ -2879,7 +2941,6 @@ http://bind10.isc.org/wiki/ScalableZoneLoadDesign#a7.2UpdatingaZone
</para>
</section>
<!-- TODO: can that retransfer be used to identify a new zone? -->
<!-- TODO: what if doesn't exist at that master IP? -->
</chapter>
......
......@@ -80,6 +80,12 @@ public:
return (FindResult());
}
}
virtual ConstZoneTableAccessorPtr
getZoneTableAccessor(const std::string&, bool) const {
isc_throw(isc::NotImplemented,
"getZoneTableAccessor not implemented for SingletonList");
}
private:
DataSourceClient& client_;
};
......
......@@ -111,7 +111,7 @@ in separate zonemgr process.
<varname>class</varname> (defaults to <quote>IN</quote>),
<varname>master_addr</varname> (the zone master to transfer from),
<varname>master_port</varname> (defaults to 53),
<varname>use_ixfr</varname> (defaults to false), and
<varname>request_ixfr</varname> (defaults to yes), and
<varname>tsig_key</varname> (optional TSIG key name to use).
The <varname>tsig_key</varname> is specified using a name that
corresponds to one of the TSIG keys configured in the global
......
This diff is collapsed.
This diff is collapsed.
......@@ -48,6 +48,11 @@
"item_type": "boolean",
"item_optional": false,
"item_default": false
},
{ "item_name": "request_ixfr",
"item_type": "string",
"item_optional": false,
"item_default": "yes"
}
]
}
......@@ -56,7 +61,36 @@
"commands": [
{
"command_name": "retransfer",
"command_description": "retransfer a single zone without checking zone serial number",
"command_description": "retransfer a single zone without checking zone serial number, always using AXFR",
"command_args": [ {
"item_name": "zone_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{
"item_name": "zone_class",
"item_type": "string",
"item_optional": true,
"item_default": "IN"
},
{
"item_name": "master",
"item_type": "string",
"item_optional": true,
"item_default": ""
},
{
"item_name": "port",
"item_type": "integer",
"item_optional": true,
"item_default": 53
}
]
},
{
"command_name": "refresh",
"command_description": "transfer a single zone with checking zone serial number and honoring the request_ixfr policy",
"command_args": [ {
"item_name": "zone_name",
"item_type": "string",
......@@ -102,16 +136,16 @@
"item_optional": false,
"item_default": {
"_SERVER_" : {
"soaoutv4": 0,
"soaoutv6": 0,
"axfrreqv4": 0,
"axfrreqv6": 0,
"ixfrreqv4": 0,
"ixfrreqv6": 0,
"xfrsuccess": 0,
"xfrfail": 0,
"last_ixfr_duration": 0.0,
"last_axfr_duration": 0.0
"soaoutv4": 0,
"soaoutv6": 0,
"axfrreqv4": 0,
"axfrreqv6": 0,
"ixfrreqv4": 0,
"ixfrreqv6": 0,
"xfrsuccess": 0,
"xfrfail": 0,
"last_ixfr_duration": 0.0,
"last_axfr_duration": 0.0
}
},
"item_title": "Zone names",
......
......@@ -80,6 +80,24 @@ is not equal to the requested SOA serial.
There was an error importing the python DNS module pydnspp. The most
likely cause is a PYTHONPATH problem.
% XFRIN_INITIAL_AXFR no SOA available for %1 yet, requesting AXFR of initial version from %2
On starting the zone transfer, it's detected that there is no SOA
record available for the zone. This is always the case for the very
first transfer or if the administrator has removed the locally copied
data by hand for some reason. In this case trying IXFR does not make
sense for the obvious reason, so AXFR will be used from the beginning,
regardless of the request_ixfr configuration (even if "only" is
specified).
% XFRIN_INITIAL_IXFR requesting IXFR for %1 from %2
IXFR will be used for the initial request type for the specified zone
transfer. It will fall back to AXFR if the initial request fails
(and unless specified not to do so by configuration).
% XFRIN_INITIAL_IXFR_DISABLED IXFR disabled for %1, requesting AXFR from %2
The use of IXFR is disabled by configuration for the specified zone,
so only AXFR will be tried.
% XFRIN_INVALID_ZONE_DATA zone %1 received from %2 is broken and unusable
The zone was received, but it failed sanity validation. The previous version
of zone (if any is available) will be used. Look for previous
......@@ -212,6 +230,17 @@ 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_FALLBACK_DISABLED suppressing fallback from IXFR to AXFR for %1
An IXFR transfer of the given zone failed. By default AXFR will be
tried next, but this fallback is disabled by configuration, so the
whole transfer attempt failed at that point. If the reason for the
failure (which should be logged separately) is temporary, this is
probably harmless or even desired as another IXFR will take place some
time later (without falling back to the possibly expensive AXFR). If
this is a permanent error (e.g., some change at the master server
completely disables IXFR), the secondary zone will eventually expire,
so the configuration should be changed to allow AXFR.
% XFRIN_XFR_TRANSFER_PROTOCOL_VIOLATION %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
......@@ -250,9 +279,9 @@ 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.
and tries to continue processing as if the zone were empty. This also
means AXFR will be used unconditionally, regardless of the configured value
for request_ixfr of the zone.
% XFRIN_ZONE_NO_SOA Zone %1 does not have SOA
On starting an xfrin session, it is identified that the zone to be
......
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2013 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
......@@ -24,6 +24,7 @@
#include <datasrc/memory/zone_data_loader.h>
#include <datasrc/memory/zone_data_updater.h>
#include <datasrc/logger.h>
#include <datasrc/zone_table_accessor_cache.h>
#include <dns/masterload.h>
#include <util/memory_segment_local.h>
......@@ -403,5 +404,30 @@ ConfigurableClientList::getStatus() const {
return (result);
}
ConstZoneTableAccessorPtr
ConfigurableClientList::getZoneTableAccessor(const std::string& datasrc_name,
bool use_cache) const
{
if (!use_cache) {
isc_throw(isc::NotImplemented,
"getZoneTableAccessor only implemented for cache");
}
// Find the matching data source
BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
if (!datasrc_name.empty() && datasrc_name != info.name_) {
continue;
}
const internal::CacheConfig* config(info.getCacheConfig());
// If caching is disabled for the named data source, this will
// return an accessor to an effectivley empty table.
return (ConstZoneTableAccessorPtr
(new internal::ZoneTableAccessorCache(*config)));
}
return (ConstZoneTableAccessorPtr());
}
}
}
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2013 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
......@@ -22,6 +22,7 @@
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include "memory/zone_table_segment.h"
#include <datasrc/zone_table_accessor.h>
#include <vector>
#include <boost/shared_ptr.hpp>
......@@ -120,6 +121,8 @@ private:
MemorySegmentState state_;
};
typedef boost::shared_ptr<const ZoneTableAccessor> ConstZoneTableAccessorPtr;
/// \brief The list of data source clients.
///
/// The purpose of this class is to hold several data source clients and search
......@@ -281,6 +284,19 @@ public:
virtual FindResult find(const dns::Name& zone,
bool want_exact_match = false,
bool want_finder = true) const = 0;
/// \brief Creates a ZoneTableAccessor object for the specified data
/// source.
///
/// \param datasrc_name If not empty, the name of the data source.
/// \param use_cache If true, create a zone table for in-memory cache.
/// \throw NotImplemented if this method is not implemented.
/// \return A pointer to the accessor, or NULL if the requested data
/// source is not found.
virtual ConstZoneTableAccessorPtr
getZoneTableAccessor(const std::string& datasrc_name,
bool use_cache) const = 0;
};
/// \brief Shared pointer to the list.
......@@ -288,8 +304,8 @@ typedef boost::shared_ptr<ClientList> ClientListPtr;
/// \brief Shared const pointer to the list.
typedef boost::shared_ptr<const ClientList> ConstClientListPtr;
/// \Concrete implementation of the ClientList, which is constructed based on
/// configuration.
/// \brief Concrete implementation of the ClientList, which is constructed
/// based on configuration.
///
/// This is the implementation which is expected to be used in the servers.
/// However, it is expected most of the code will use it as the ClientList,
......@@ -490,6 +506,22 @@ public:
/// it might be, so it is just made public (there's no real reason to
/// hide it).
const DataSources& getDataSources() const { return (data_sources_); }
/// \brief Creates a ZoneTableAccessor object for the specified data
/// source.
///
/// \param datasrc_name If not empty, the name of the data source
/// \param use_cache If true, create a zone table for in-memory cache.
/// \note At present, the only concrete implementation of
/// ZoneTableAccessor is ZoneTableAccessorCache, so \c use_cache must be
/// true.
/// \throw NotImplemented if \c use_cache is false.
/// \return A pointer to the accessor, or NULL if the requested data
/// source is not found.
ConstZoneTableAccessorPtr
getZoneTableAccessor(const std::string& datasrc_name,
bool use_cache) const;
private:
struct MutableResult;
/// \brief Internal implementation of find.
......
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2013 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
......@@ -266,6 +266,8 @@ public:
}
ConfigurableClientList::CacheStatus doReload(
const Name& origin, const string& datasrc_name = "");
void accessorIterate(const ConstZoneTableAccessorPtr& accessor,
int numZones, const string& zoneName);
const RRClass rrclass_;
shared_ptr<TestedList> list_;
......@@ -1147,6 +1149,93 @@ TEST_F(ListTest, reloadByDataSourceName) {
doReload(Name("example.org"), "test_type4"));
}
// This takes the accessor provided by getZoneTableAccessor(), iterates
// through the table, and verifies that the expected number of zones are
// present, as well as the named zone.
void
ListTest::accessorIterate(const ConstZoneTableAccessorPtr& accessor,
int numZones, const string& zoneName="")
{
// Confirm basic iterator behavior.
ASSERT_TRUE(accessor);
ZoneTableAccessor::IteratorPtr it = accessor->getIterator();
ASSERT_TRUE(it);
// Iterator does not guarantee ordering, so we look for the target
// name anywhere in the table.
bool found = false;
int i;
for (i = 0; !it->isLast(); ++i, it->next()) {
if (Name(zoneName) == it->getCurrent().origin) {
found = true;
}
}
EXPECT_EQ(i, numZones);
if (numZones > 0) {
EXPECT_TRUE(found);
}
}
TEST_F(ListTest, zoneTableAccessor) {
// empty configuration
const ConstElementPtr elem(new ListElement);
list_->configure(elem, true);
// null pointer treated as false
EXPECT_FALSE(list_->getZoneTableAccessor("", true));
// empty list; expect it to return an empty list
list_->configure(config_elem_, true);
ConstZoneTableAccessorPtr z(list_->getZoneTableAccessor("", true));
accessorIterate(z, 0);
const ConstElementPtr elem2(Element::fromJSON("["
"{"
" \"type\": \"type1\","
" \"cache-enable\": true,"
" \"cache-zones\": [\"example.com\"],"
" \"params\": [\"example.com\"]"
"},"
"{"
" \"type\": \"type2\","
" \"cache-enable\": false,"
" \"params\": [\"example.org\"]"
"},"
"{"
" \"type\": \"type3\","
" \"cache-enable\": true,"
" \"cache-zones\": [\"example.net\", \"example.info\"],"
" \"params\": [\"example.net\", \"example.info\"]"
"}]"));
// allow_cache = false
// ask for a non-existent zone table, expect null
list_->configure(elem2, false);
EXPECT_FALSE(list_->getZoneTableAccessor("bogus", true));
// ask for any zone table, expect an empty list
z = list_->getZoneTableAccessor("", true);
accessorIterate(z, 0);
// allow_cache = true, use_cache = false
list_->configure(elem2, true);
EXPECT_THROW(list_->getZoneTableAccessor("", false), isc::NotImplemented);
EXPECT_THROW(list_->getZoneTableAccessor("type1", false),
isc::NotImplemented);
// datasrc not found, returns NULL pointer
EXPECT_FALSE(list_->getZoneTableAccessor("bogus", true));
// return first datasrc
z = list_->getZoneTableAccessor("", true);
accessorIterate(z, 1, "example.com");
// datasrc has cache disabled, returns accessor to empty list
z = list_->getZoneTableAccessor("type2", true);
accessorIterate(z, 0);
// search by name
z = list_->getZoneTableAccessor("type3", true);
accessorIterate(z, 2, "example.net");
}
// Check the status holds data
TEST(DataSourceStatus, status) {
const DataSourceStatus status("Test", SEGMENT_INUSE, "local");
......
......@@ -2,7 +2,6 @@
"Xfrin": {
"zones": [
{
"use_ixfr": true,
"class": "IN",
"name": "example.com.",
"master_addr": "178.18.82.80"
......
......@@ -18,8 +18,7 @@
"zones": [ {
"name": "example",
"master_addr": "::1",
"master_port": 47807,
"use_ixfr": true
"master_port": 47807
} ]
},
"data_sources": {
......
......@@ -28,7 +28,8 @@
"zones": [ {
"name": "example.org",
"master_addr": "::1",
"master_port": 47807
"master_port": 47807,
"request_ixfr": "no"
} ]
},
"Zonemgr": {
......
......@@ -28,7 +28,8 @@
"zones": [ {
"name": "example.org",
"master_addr": "127.0.0.1",
"master_port": 47809
"master_port": 47809,
"request_ixfr": "no"
} ]
},
"Zonemgr": {
......
......@@ -182,7 +182,8 @@ Feature: Xfrin
example. 3600 IN SOA ns1.example. hostmaster.example. 94 3600 900 7200 300
"""
When I send bind10 the command Xfrin retransfer example. IN ::1 47807
# To invoke IXFR we need to use refresh command
When I send bind10 the command Xfrin refresh example. IN ::1 47807
Then wait for new bind10 stderr message XFRIN_GOT_INCREMENTAL_RESP
Then wait for new bind10 stderr message XFRIN_IXFR_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
# This can't be 'wait for new'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment