diff --git a/repos/os/src/server/nic_router/README b/repos/os/src/server/nic_router/README
index 1f317f77d8..4f937fc42e 100644
--- a/repos/os/src/server/nic_router/README
+++ b/repos/os/src/server/nic_router/README
@@ -292,18 +292,26 @@ this:
+ dns_server="10.0.0.2"
+ dns_server_from="uplink" />
...
-The attributes ip_first and ip_last define the available IPv4 address
-range while ip_lease_time_sec defines the lifetime of an IPv4 address
-assignment in seconds. The IPv4 address range must be in the subnet
-defined by the interface attribute of the domain tag and must not cover
-the IPv4 address in this attribute. The dns_server attribute gives the
-IPv4 address of the DNS server that might also be in another subnet.
-The lifetime of an assignment that was yet only offered to the client
-can be configured for all domains in the tag of the router:
+The attributes ip_first and ip_last define the available IPv4 address range
+while ip_lease_time_sec defines the lifetime of an IPv4 address assignment in
+seconds. The IPv4 address range must be in the subnet defined by the interface
+attribute of the domain tag and must not cover the IPv4 address in this
+attribute. The dns_server attribute gives the IPv4 address of the DNS server
+that might also be in another subnet. The dns_server_from attribute has effect
+only if the dns_server attribute is not set. If this is the case, the
+dns_server_from attribute states the domain from whose IP config to take the
+DNS server address. This is useful, for instance, if the stated domain
+receives the address of a local DNS server via DHCP. Whenever the IP config
+of the stated domain becomes invalid, the DHCP server switches to a mode where
+it drops all requests unanswered until the IP config becomes valid again.
+
+The lifetime of an assignment that was yet only offered to the client can be
+configured for all domains in the tag of the router:
!
diff --git a/repos/os/src/server/nic_router/config.xsd b/repos/os/src/server/nic_router/config.xsd
index 3f731025a7..caef35ac67 100644
--- a/repos/os/src/server/nic_router/config.xsd
+++ b/repos/os/src/server/nic_router/config.xsd
@@ -131,6 +131,7 @@
+
diff --git a/repos/os/src/server/nic_router/dhcp_server.cc b/repos/os/src/server/nic_router/dhcp_server.cc
index ed1bc1a169..25787a42b2 100644
--- a/repos/os/src/server/nic_router/dhcp_server.cc
+++ b/repos/os/src/server/nic_router/dhcp_server.cc
@@ -14,6 +14,7 @@
/* local includes */
#include
#include
+#include
using namespace Net;
using namespace Genode;
@@ -25,10 +26,12 @@ using namespace Genode;
Dhcp_server::Dhcp_server(Xml_node const node,
Allocator &alloc,
- Ipv4_address_prefix const &interface)
+ Ipv4_address_prefix const &interface,
+ Domain_tree &domains)
:
_dns_server(node.attribute_value("dns_server", Ipv4_address())),
- _ip_lease_time(_init_ip_lease_time(node)),
+ _dns_server_from(_init_dns_server_from(node, domains)),
+ _ip_lease_time (_init_ip_lease_time(node)),
_ip_first(node.attribute_value("ip_first", Ipv4_address())),
_ip_last(node.attribute_value("ip_last", Ipv4_address())),
_ip_first_raw(_ip_first.to_uint32_little_endian()),
@@ -59,8 +62,11 @@ Microseconds Dhcp_server::_init_ip_lease_time(Xml_node const node)
void Dhcp_server::print(Output &output) const
{
if (_dns_server.valid()) {
- Genode::print(output, "DNS server ", _dns_server, " ");
+ Genode::print(output, "DNS server ", _dns_server, ", ");
}
+ try { Genode::print(output, "DNS server from ", _dns_server_from(), ", "); }
+ catch (Pointer::Invalid) { }
+
Genode::print(output, "IP first ", _ip_first,
", last ", _ip_last,
", count ", _ip_count,
@@ -94,6 +100,42 @@ void Dhcp_server::free_ip(Ipv4_address const &ip)
}
+Pointer Dhcp_server::_init_dns_server_from(Genode::Xml_node const node,
+ Domain_tree &domains)
+{
+ if (_dns_server.valid()) {
+ return Pointer();
+ }
+ Domain_name dns_server_from =
+ node.attribute_value("dns_server_from", Domain_name());
+
+ if (dns_server_from == Domain_name()) {
+ return Pointer();
+ }
+ try { return domains.find_by_name(dns_server_from); }
+ catch (Domain_tree::No_match) { throw Invalid(); }
+}
+
+
+Ipv4_address const &Dhcp_server::dns_server() const
+{
+ try { return _dns_server_from().ip_config().dns_server; }
+ catch (Pointer::Invalid) { }
+ return _dns_server;
+}
+
+
+bool Dhcp_server::ready() const
+{
+ if (_dns_server.valid()) {
+ return true;
+ }
+ try { return _dns_server_from().ip_config().valid; }
+ catch (Pointer::Invalid) { }
+ return true;
+}
+
+
/*********************
** Dhcp_allocation **
*********************/
diff --git a/repos/os/src/server/nic_router/dhcp_server.h b/repos/os/src/server/nic_router/dhcp_server.h
index 08835da314..6da911cfed 100644
--- a/repos/os/src/server/nic_router/dhcp_server.h
+++ b/repos/os/src/server/nic_router/dhcp_server.h
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
/* Genode includes */
#include
@@ -35,6 +36,8 @@ namespace Net {
/* forward declarations */
class Interface;
+ class Domain;
+ class Domain_tree;
}
@@ -43,6 +46,7 @@ class Net::Dhcp_server : private Genode::Noncopyable
private:
Ipv4_address const _dns_server;
+ Pointer const _dns_server_from;
Genode::Microseconds const _ip_lease_time;
Ipv4_address const _ip_first;
Ipv4_address const _ip_last;
@@ -52,6 +56,9 @@ class Net::Dhcp_server : private Genode::Noncopyable
Genode::Microseconds _init_ip_lease_time(Genode::Xml_node const node);
+ Pointer _init_dns_server_from(Genode::Xml_node const node,
+ Domain_tree &domains);
+
public:
enum { DEFAULT_IP_LEASE_TIME_SEC = 3600 };
@@ -61,7 +68,8 @@ class Net::Dhcp_server : private Genode::Noncopyable
Dhcp_server(Genode::Xml_node const node,
Genode::Allocator &alloc,
- Ipv4_address_prefix const &interface);
+ Ipv4_address_prefix const &interface,
+ Domain_tree &domains);
Ipv4_address alloc_ip();
@@ -69,6 +77,8 @@ class Net::Dhcp_server : private Genode::Noncopyable
void free_ip(Ipv4_address const &ip);
+ bool ready() const;
+
/*********
** log **
@@ -81,7 +91,7 @@ class Net::Dhcp_server : private Genode::Noncopyable
** Accessors **
***************/
- Ipv4_address const &dns_server() const { return _dns_server; }
+ Ipv4_address const &dns_server() const;
Genode::Microseconds ip_lease_time() const { return _ip_lease_time; }
};
diff --git a/repos/os/src/server/nic_router/domain.cc b/repos/os/src/server/nic_router/domain.cc
index c0c0fc40d0..95c2f2a79c 100644
--- a/repos/os/src/server/nic_router/domain.cc
+++ b/repos/os/src/server/nic_router/domain.cc
@@ -128,7 +128,6 @@ Domain::Domain(Configuration &config, Xml_node const node, Allocator &alloc)
if (_config.verbose_domain_state()) {
log("[", *this, "] NIC sessions: ", _interface_cnt);
}
- _ip_config_changed();
}
@@ -188,6 +187,16 @@ void Domain::__FIXME__dissolve_foreign_arp_waiters()
}
+Dhcp_server &Domain::dhcp_server()
+{
+ Dhcp_server &dhcp_server = _dhcp_server();
+ if (!dhcp_server.ready()) {
+ throw Pointer::Invalid();
+ }
+ return dhcp_server;
+}
+
+
void Domain::init(Domain_tree &domains)
{
/* read DHCP server configuration */
@@ -198,7 +207,8 @@ void Domain::init(Domain_tree &domains)
throw Invalid();
}
_dhcp_server = *new (_alloc)
- Dhcp_server(dhcp_server_node, _alloc, ip_config().interface);
+ Dhcp_server(dhcp_server_node, _alloc, ip_config().interface,
+ domains);
if (_config.verbose()) {
log("[", *this, "] DHCP server: ", _dhcp_server()); }
diff --git a/repos/os/src/server/nic_router/domain.h b/repos/os/src/server/nic_router/domain.h
index 47d4129e9b..29f063ba8f 100644
--- a/repos/os/src/server/nic_router/domain.h
+++ b/repos/os/src/server/nic_router/domain.h
@@ -180,7 +180,7 @@ class Net::Domain : public Domain_base
Interface_list &interfaces() { return _interfaces; }
Configuration &config() const { return _config; }
Domain_avl_member &avl_member() { return _avl_member; }
- Dhcp_server &dhcp_server() { return _dhcp_server(); }
+ Dhcp_server &dhcp_server();
Arp_cache &arp_cache() { return _arp_cache; }
Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; }
Link_side_tree &tcp_links() { return _tcp_links; }