nic_router: multiple uplinks

Introduce the uplink tag:

! <config>
!    <uplink label="wifi"  domain="uplink">
!    <uplink label="wired" domain="wired_bridge">
!    <uplink               domain="wired_bridge">
! <config/>

For each uplink tag, the NIC router requests a NIC session with the
corresponding label or an empty label if there is no label attribute.
These NIC sessions get attached to the domain that is set in their
uplink tag as soon as the domain appears. This means their lifetime is
not bound to the domain. Uplink NIC sessions can be safely moved from
one domain to another without being closed by reconfiguring the
corresponding domain attribute.

Attention: This may render previously valid NIC router configurations
useless. A domain named "uplink" doesn't automatically request a NIC
session anymore. To fix these configurations, just add

! <uplink domain="uplink"/>

or

! <uplink label="[LABEL]" domain="uplink"/>

as direct subtag of the <config> tag.

Issue #2840
This commit is contained in:
Martin Stein 2018-06-05 18:31:40 +02:00 committed by Norman Feske
parent d4f08b5a71
commit 49a3a0e0d0
23 changed files with 418 additions and 201 deletions

View File

@ -125,8 +125,9 @@ append config {
<inline>
<config dhcp_discover_timeout_sec="1">
<default-policy domain="downlink"/>
<domain name="uplink" label="nic">
<default-policy domain="downlink"/>
<uplink label="nic" domain="uplink" />
<domain name="uplink">
<nat domain="downlink" icmp-ids="999"/>
</domain>
<domain name="downlink" interface="10.0.1.79/24">
@ -140,8 +141,9 @@ append config {
<inline>
<config dhcp_discover_timeout_sec="1">
<default-policy domain="downlink"/>
<domain name="uplink" label="wifi">
<default-policy domain="downlink"/>
<uplink label="wifi" domain="uplink" />
<domain name="uplink">
<nat domain="downlink" icmp-ids="999"/>
</domain>
<domain name="downlink" interface="10.0.1.79/24">
@ -167,8 +169,9 @@ append config {
<inline>
<config dhcp_discover_timeout_sec="1">
<default-policy domain="downlink"/>
<domain name="uplink" label="nic">
<default-policy domain="downlink"/>
<uplink label="nic" domain="uplink" />
<domain name="uplink">
<nat domain="downlink" icmp-ids="999"/>
</domain>
<domain name="downlink" interface="10.0.1.79/24">
@ -182,8 +185,9 @@ append config {
<inline>
<config dhcp_discover_timeout_sec="1">
<default-policy domain="downlink"/>
<domain name="uplink" label="nic">
<default-policy domain="downlink"/>
<uplink label="nic" domain="uplink" />
<domain name="uplink">
<nat domain="downlink" icmp-ids="999"/>
</domain>
<domain name="downlink" interface="10.0.1.79/24">
@ -209,8 +213,9 @@ append config {
<inline>
<config dhcp_discover_timeout_sec="1">
<default-policy domain="downlink"/>
<domain name="uplink" label="wifi">
<default-policy domain="downlink"/>
<uplink label="wifi" domain="uplink" />
<domain name="uplink">
<nat domain="downlink" icmp-ids="999"/>
</domain>
<domain name="downlink" interface="10.0.1.79/24">
@ -224,8 +229,9 @@ append config {
<inline>
<config dhcp_discover_timeout_sec="1">
<default-policy domain="downlink"/>
<domain name="uplink" label="nic">
<default-policy domain="downlink"/>
<uplink label="nic" domain="uplink" />
<domain name="uplink">
<nat domain="downlink" icmp-ids="999"/>
</domain>
<domain name="downlink" interface="10.0.1.79/24">

View File

@ -15,6 +15,24 @@
#include <network.h>
void Sculpt::Network::_generate_nic_router_uplink(Xml_generator &xml,
char const *label)
{
xml.node("uplink", [&] () {
xml.attribute("label", label);
xml.attribute("domain", "uplink");
});
gen_named_node(xml, "domain", "uplink", [&] () {
xml.node("nat", [&] () {
xml.attribute("domain", "default");
xml.attribute("tcp-ports", "1000");
xml.attribute("udp-ports", "1000");
xml.attribute("icmp-ids", "1000");
});
});
}
void Sculpt::Network::handle_key_press(Codepoint code)
{
enum { BACKSPACE = 8, ENTER = 10 };
@ -70,22 +88,12 @@ void Sculpt::Network::_generate_nic_router_config()
xml.node("default-policy", [&] () {
xml.attribute("domain", "default"); });
if (_nic_target.type() != Nic_target::LOCAL) {
gen_named_node(xml, "domain", "uplink", [&] () {
switch (_nic_target.type()) {
case Nic_target::WIRED: xml.attribute("label", "wired"); break;
case Nic_target::WIFI: xml.attribute("label", "wifi"); break;
default: break;
}
xml.node("nat", [&] () {
xml.attribute("domain", "default");
xml.attribute("tcp-ports", "1000");
xml.attribute("udp-ports", "1000");
xml.attribute("icmp-ids", "1000");
});
});
bool uplink_exists = true;
switch (_nic_target.type()) {
case Nic_target::WIRED: _generate_nic_router_uplink(xml, "wired"); break;
case Nic_target::WIFI: _generate_nic_router_uplink(xml, "wifi"); break;
default: uplink_exists = false;
}
gen_named_node(xml, "domain", "default", [&] () {
xml.attribute("interface", "10.0.1.1/24");
@ -96,7 +104,7 @@ void Sculpt::Network::_generate_nic_router_config()
xml.attribute("dns_server_from", "uplink"); }
});
if (_nic_target.type() != Nic_target::LOCAL) {
if (uplink_exists) {
xml.node("tcp", [&] () {
xml.attribute("dst", "0.0.0.0/0");
xml.node("permit-any", [&] () {
@ -171,19 +179,31 @@ void Sculpt::Network::_handle_nic_router_config(Xml_node config)
if (!config.has_sub_node("domain"))
target = Nic_target::OFF;
config.for_each_sub_node("domain", [&] (Xml_node domain) {
struct Break : Exception { };
try {
config.for_each_sub_node("domain", [&] (Xml_node domain) {
/* skip non-uplink domains */
if (domain.attribute_value("name", String<16>()) != "uplink")
return;
/* skip domains that are not called "uplink" */
if (domain.attribute_value("name", String<16>()) != "uplink")
return;
if (domain.attribute_value("label", String<16>()) == "wired")
target = Nic_target::WIRED;
config.for_each_sub_node("uplink", [&] (Xml_node uplink) {
if (domain.attribute_value("label", String<16>()) == "wifi")
target = Nic_target::WIFI;
});
/* skip uplinks not assigned to a domain called "uplink" */
if (uplink.attribute_value("domain", String<16>()) != "uplink")
return;
if (uplink.attribute_value("label", String<16>()) == "wired") {
target = Nic_target::WIRED;
throw Break();
}
if (uplink.attribute_value("label", String<16>()) == "wifi") {
target = Nic_target::WIFI;
throw Break();
}
});
});
} catch (Break) { }
_nic_target.manual_type = target;
}

View File

@ -63,6 +63,9 @@ struct Sculpt::Network : Network_dialog::Action
void _generate_nic_router_config();
void _generate_nic_router_uplink(Xml_generator &xml,
char const *label);
Access_points _access_points { };
Wifi_connection _wifi_connection = Wifi_connection::disconnected_wifi_connection();

View File

@ -88,6 +88,7 @@ append config {
<policy label_prefix="http_server_2" domain="http_server_2" />
<policy label_prefix="udp_server_1" domain="udp_server_1" />
<policy label_prefix="udp_server_2" domain="udp_server_2" />
<uplink domain="uplink" />
<domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1">
<tcp-forward port="80" domain="http_server_1" to="192.168.1.18" />

View File

@ -158,6 +158,7 @@ proc test_7_config { } {
<config>
<policy label_prefix="lan_2" domain="downlink" />
<uplink domain="uplink" />
<domain name="uplink">
<nat domain="downlink" tcp-ports="6" />
@ -260,6 +261,8 @@ append config {
<report bytes="yes" config="yes" interval_sec="60" />
<uplink domain="uplink"/>
<domain name="uplink"
interface="10.0.2.55/24"
gateway="10.0.2.1"

View File

@ -230,6 +230,8 @@ append config {
<report/>
<uplink domain="uplink"/>
<domain name="uplink"
interface="10.0.2.55/24"
gateway="10.0.2.1"
@ -266,6 +268,8 @@ append config {
tcp_idle_timeout_sec="30"
tcp_max_segm_lifetime_sec="15">
<uplink domain="uplink"/>
<domain name="uplink"
interface="10.0.2.55/24"
gateway="10.0.2.1"
@ -306,6 +310,8 @@ append config {
<report interval_sec="2" bytes="yes" config="no" />
<uplink domain="uplink"/>
<domain name="uplink"
interface="10.0.2.55/24"
gateway="10.0.2.1"
@ -338,6 +344,8 @@ append config {
<report interval_sec="2" bytes="yes" config="no" />
<uplink domain="uplink"/>
<domain name="uplink"
interface="10.0.2.55/24"
gateway="10.0.2.1"

View File

@ -5,6 +5,7 @@
<config verbose_domain_state="yes">
<default-policy domain="default" />
<uplink domain="uplink" />
<domain name="uplink">
<nat domain="default"
tcp-ports="1000"

View File

@ -93,6 +93,7 @@ append config {
<policy label_prefix="flood_links" domain="flood_links"/>
<policy label_prefix="ping" domain="flood_links"/>
<uplink domain="uplink"/>
<domain name="uplink" verbose_packets="no">
<nat domain="flood_links" udp-ports="16384"

View File

@ -98,6 +98,7 @@ append config {
<policy label_prefix="ping_1" domain="ping_1"/>
<policy label_prefix="ping_2" domain="ping_2"/>
<uplink domain="uplink"/>
<domain name="uplink">
<nat domain="ping_1" icmp-ids="100"/>
@ -131,6 +132,7 @@ append config {
icmp_idle_timeout_sec="10">
<policy label_prefix="ping_2" domain="ping_2"/>
<uplink domain="uplink"/>
<domain name="uplink" interface="10.0.4.2/24" gateway="10.0.4.1">
<nat domain="ping_2" icmp-ids="100" udp-ports="100"/>

View File

@ -19,22 +19,35 @@ these domains. This is a brief overview of the features thereby provided:
Basics
~~~~~~
The 'nic_router' component provides multiple sessions of the 'NIC' service
(downlinks) while requesting one 'NIC' session (the uplink) itself. Through
common Genode session routing, the uplink can be connected to any other NIC
server. Inside the component, uplink and downlinks are treated the same. Its
routing algorithm is ultimately controlled through the configuration. NIC
The NIC router can act as server of multiple NIC session clients (downlinks)
and at the same time as client of multiple NIC session servers (uplinks).
Besides the decision which side initiates the NIC session and provides MAC
address respectively link state, uplinks and downlinks are equal to the NIC
router.
The routing algorithm is ultimately controlled through the configuration. NIC
sessions are assigned to domains. Each domain represents one subnet and a
corresponding routing configuration. Currently, each domain can contain
only one NIC session at a time. The assignment of sessions to domains is
controlled through the the common Genode session-policy tag:
corresponding routing configuration. The assignment of downlink NIC sessions
to domains is controlled through the policy tag that is also known from other
Genode components:
! <policy label_prefix="http_server" domain="http_servers" />
! <policy label_prefix="imap_server" domain="imap_servers" />
! <policy label_prefix="vlan_" domain="vlan" />
! <policy label_suffix="_server" domain="servers" />
! <policy label="nic_bridge_1" domain="wired_bridge" />
! <policy label="nic_bridge_2" domain="wired_bridge" />
The domain name can be freely choosen but must be unique. There is no need
to have a policy for the uplink. It is automatically assigned to the domain
named "uplink". For each domain there must be a domain tag:
The domain name can be freely choosen but must be unique.
The uplink tag instructs the NIC router to create an uplink NIC session that
is assigned to the give domain:
! <uplink domain="wired_bridge" />
! <uplink label="wired" domain="wired_bridge" />
! <uplink label="wifi" domain="wifi_uplink" />
The label is the session label that is used when requesting the uplink NIC
session. The label attribute is optional. It is perfectly fine to have a
domain with uplinks and downlinks assigned to at the same time. For each
domain there must be a domain tag:
! <domain name="uplink" interface="10.0.2.55/24" />
! <domain name="http_servers" interface="192.168.1.18/24" />
@ -411,27 +424,6 @@ router:
! dhcp_request_timeout_sec="6">
The uplink domain
~~~~~~~~~~~~~~~~~
The uplink domain is treated like every other domain wherever possible.
However, there are still some differences that are visible to the user:
* 'policy' tags that target the uplink domain have no effect at all
* The domain tag of the uplink is the only domain tag in which the
'label' attribute has an effect
* The uplink domain, as long as existant, has exactly one NIC session in which
the NIC router is the session client
* When the uplink 'domain' tag appears, the uplink NIC session is requested by
the NIC router using the label denoted in the 'label' attribute of the
uplink 'domain' tag (default label "")
* When the 'label' attribute of the uplink 'domain' tag changes, the NIC
router closes the uplink NIC session and requests it again with the new
label
* When the uplink 'domain' tag disappears, the NIC router closes the uplink
NIC session
Configuring reporting functionality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -511,6 +503,7 @@ following configuration:
! <policy label_prefix="virtnet_a" domain="virtnet_a" />
! <policy label_prefix="virtnet_b" domain="virtnet_b" />
! <uplink domain="uplink" />
!
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1/24">
! <ip dst="192.168.1.0/24" domain="virtnet_a"/>
@ -550,6 +543,7 @@ internet. The router would have the following configuration:
! <policy label_prefix="virtnet_a" domain="virtnet_a" />
! <policy label_prefix="virtnet_b" domain="virtnet_b" />
! <uplink domain="uplink" />
!
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1/24">
! <nat domain="virtnet_a" tcp_ports="1000" udp_ports="1000">
@ -588,6 +582,7 @@ following configuration:
! <policy label_prefix="virtnet_a" domain="virtnet_a" />
! <policy label_prefix="virtnet_b" domain="virtnet_b" />
! <uplink domain="uplink" />
!
! <domain name="uplink" interface="10.0.2.55/24" gateway="10.0.2.1">
! <tcp-forward port="80" domain="virtnet_a" to="192.168.1.2" />

View File

@ -101,6 +101,8 @@ Net::Session_component::Session_component(Allocator &alloc,
config, interfaces, *_tx.sink(), *_rx.source(),
_link_state, _interface_policy }
{
_interface.attach_to_domain();
_tx.sigh_ready_to_ack (_interface.sink_ack());
_tx.sigh_packet_avail (_interface.sink_submit());
_rx.sigh_ack_avail (_interface.source_ack());

View File

@ -112,6 +112,13 @@
</xs:complexType>
</xs:element><!-- policy -->
<xs:element name="uplink">
<xs:complexType>
<xs:attribute name="label" type="Session_label" />
<xs:attribute name="domain" type="Domain_name" />
</xs:complexType>
</xs:element><!-- uplink -->
<xs:element name="domain">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">

View File

@ -35,6 +35,17 @@ Configuration::Configuration(Xml_node const node,
{ }
void Configuration::_invalid_uplink(Uplink &uplink,
char const *reason)
{
if (_verbose) {
log("[", uplink.domain(), "] invalid uplink: ", uplink, " (", reason, ")"); }
_uplinks.remove(uplink);
destroy(_alloc, &uplink);
}
void Configuration::_invalid_domain(Domain &domain,
char const *reason)
{
@ -50,7 +61,8 @@ Configuration::Configuration(Env &env,
Xml_node const node,
Allocator &alloc,
Timer::Connection &timer,
Configuration &old_config)
Configuration &old_config,
Interface_list &interfaces)
:
_alloc(alloc),
_verbose (node.attribute_value("verbose", false)),
@ -129,11 +141,35 @@ Configuration::Configuration(Env &env,
Report(report_node, timer, _domains, _reporter());
}
catch (Genode::Xml_node::Nonexistent_sub_node) { }
/* initialize uplinks */
_node.for_each_sub_node("uplink", [&] (Xml_node const node) {
try {
Uplink &uplink = *new (_alloc)
Uplink { node, alloc, old_config._uplinks, env, timer,
interfaces, *this };
try { _uplinks.insert(uplink); }
catch (Uplink_tree::Name_not_unique exception) {
_invalid_uplink(uplink, "label not unique");
_invalid_uplink(exception.object, "label not unique");
}
}
catch (Uplink::Invalid) { }
});
/*
* Destroy old uplinks to ensure that uplink interfaces that were not
* re-used are not re-attached to the new domains.
*/
old_config._uplinks.destroy_each(_alloc);
}
Configuration::~Configuration()
{
/* destroy uplinks */
_uplinks.destroy_each(_alloc);
/* destroy reporter */
try { destroy(_alloc, &_reporter()); }
catch (Pointer<Reporter>::Invalid) { }

View File

@ -17,6 +17,7 @@
/* local includes */
#include <domain.h>
#include <report.h>
#include <uplink.h>
/* Genode includes */
#include <os/duration.h>
@ -46,8 +47,12 @@ class Net::Configuration
Pointer<Report> _report { };
Pointer<Genode::Reporter> _reporter { };
Domain_tree _domains { };
Uplink_tree _uplinks { };
Genode::Xml_node const _node;
void _invalid_uplink(Uplink &uplink,
char const *reason);
void _invalid_domain(Domain &domain,
char const *reason);
@ -69,7 +74,8 @@ class Net::Configuration
Genode::Xml_node const node,
Genode::Allocator &alloc,
Timer::Connection &timer,
Configuration &old_config);
Configuration &old_config,
Interface_list &interfaces);
~Configuration();

View File

@ -30,6 +30,7 @@ using Genode::uint32_t;
using Genode::log;
using Genode::error;
using Genode::warning;
using Genode::Exception;
using Genode::construct_at;
using Genode::Quota_guard;
using Genode::Ram_quota;
@ -256,15 +257,23 @@ void Interface::_detach_from_domain_raw()
}
void Interface::_attach_to_domain(Domain_name const &domain_name)
void Interface::attach_to_domain()
{
_attach_to_domain_raw(_config().domains().find_by_name(domain_name));
attach_to_domain_finish();
try {
_attach_to_domain_raw(_config().domains().find_by_name(
_policy.determine_domain_name()));
attach_to_domain_finish();
}
catch (Domain_tree::No_match) { }
}
void Interface::attach_to_domain_finish()
{
if (!link_state()) {
return; }
/* if domain has yet no IP config, participate in requesting one */
Domain &domain = _domain();
Ipv4_config const &ip_config = domain.ip_config();
@ -764,6 +773,27 @@ bool Interface::link_state() const
}
void Interface::handle_link_state()
{
struct Keep_ip_config : Exception { };
try {
attach_to_domain_finish();
/* if the wholde domain became down, discard IP config */
Domain &domain_ = domain();
if (!link_state() && domain_.ip_config().valid) {
domain_.interfaces().for_each([&] (Interface &interface) {
if (interface.link_state()) {
throw Keep_ip_config(); }
});
domain_.discard_ip_config();
}
}
catch (Domain::Ip_config_static) { }
catch (Keep_ip_config) { }
}
void Interface::_handle_icmp_query(Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
@ -1383,8 +1413,6 @@ Interface::Interface(Genode::Entrypoint &ep,
_interfaces { interfaces }
{
_interfaces.insert(this);
try { _attach_to_domain(_policy.determine_domain_name()); }
catch (Domain_tree::No_match) { }
}

View File

@ -274,8 +274,6 @@ class Net::Interface : private Interface_list::Element
void _detach_from_domain();
void _attach_to_domain(Domain_name const &domain_name);
void _attach_to_domain_raw(Domain &domain);
void _apply_foreign_arp();
@ -375,6 +373,8 @@ class Net::Interface : private Interface_list::Element
void handle_config_3();
void attach_to_domain();
void detach_from_ip_config();
void attach_to_ip_config(Domain &domain,
@ -388,6 +388,8 @@ class Net::Interface : private Interface_list::Element
bool link_state() const;
void handle_link_state();
/***************
** Accessors **

View File

@ -38,22 +38,12 @@ class Net::Main
Timer::Connection _timer { _env };
Genode::Heap _heap { &_env.ram(), &_env.rm() };
Genode::Attached_rom_dataspace _config_rom { _env, "config" };
Reference<Configuration> _config { _init_config() };
Reference<Configuration> _config { *new (_heap) Configuration { _config_rom.xml(), _heap } };
Signal_handler<Main> _config_handler { _env.ep(), *this, &Main::_handle_config };
Pointer<Uplink> _uplink { };
Root _root { _env.ep(), _timer, _heap, _config(), _env.ram(), _interfaces, _env.rm()};
void _handle_config();
Configuration &_init_config();
void _deinit_uplink(Configuration &config);
void _init_uplink(Configuration &config,
Session_label const &label);
void _uplink_handle_config(Configuration &config);
template <typename FUNC>
void _for_each_interface(FUNC && functor)
{
@ -73,80 +63,22 @@ class Net::Main
};
Configuration &Net::Main::_init_config()
{
Configuration &dummy_config = *new (_heap)
Configuration(_config_rom.xml(), _heap);
Configuration &config = *new (_heap)
Configuration(_env, _config_rom.xml(), _heap, _timer, dummy_config);
destroy(_heap, &dummy_config);
return config;
}
Net::Main::Main(Env &env) : _env(env)
{
_uplink_handle_config(_config());
_config_rom.sigh(_config_handler);
_handle_config();
env.parent().announce(env.ep().manage(_root));
}
void Net::Main::_init_uplink(Configuration &config,
Session_label const &label)
{
if (config.verbose()) {
log("[uplink] request NIC session \"", label, "\""); }
Uplink &uplink = *new (_heap) Uplink(_env, _timer, _heap, _interfaces,
config, label);
_uplink = Pointer<Uplink>(uplink);
}
void Net::Main::_deinit_uplink(Configuration &config)
{
try {
Uplink &uplink = _uplink();
if (config.verbose()) {
log("[uplink] close NIC session \"", uplink.label(), "\""); }
destroy(_heap, &uplink);
_uplink = Pointer<Uplink>();
}
catch (Pointer<Uplink>::Invalid) { }
}
void Net::Main::_uplink_handle_config(Configuration &config)
{
try {
Session_label const &label =
config.domains().find_by_name("uplink").label();
try {
if (label == _uplink().label()) {
return;
}
_deinit_uplink(config);
_init_uplink(config, label);
}
catch (Pointer<Uplink>::Invalid) { _init_uplink(config, label); }
}
catch (Domain_tree::No_match) { _deinit_uplink(config); }
}
void Net::Main::_handle_config()
{
_config_rom.update();
Configuration &old_config = _config();
Configuration &new_config = *new (_heap)
Configuration(_env, _config_rom.xml(), _heap, _timer, old_config);
Configuration(_env, _config_rom.xml(), _heap, _timer, old_config,
_interfaces);
_uplink_handle_config(new_config);
_root.handle_config(new_config);
_for_each_interface([&] (Interface &intf) { intf.handle_config_1(new_config); });
_for_each_interface([&] (Interface &intf) { intf.handle_config_2(); });
@ -157,12 +89,4 @@ void Net::Main::_handle_config()
}
void Component::construct(Env &env)
{
try { static Net::Main main(env); }
catch (Net::Domain_tree::No_match) {
error("failed to find configuration for domain 'uplink'");
env.parent().exit(-1);
}
}
void Component::construct(Env &env) { static Net::Main main(env); }

View File

@ -13,7 +13,6 @@
/* Genode includes */
#include <base/env.h>
#include <net/ethernet.h>
/* local includes */
#include <uplink.h>
@ -23,20 +22,111 @@ using namespace Net;
using namespace Genode;
Net::Uplink::Uplink(Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Session_label const &label)
/*****************
** Uplink_base **
*****************/
Net::Uplink_base::Uplink_base(Xml_node const &node)
:
_label { node.attribute_value("label", Session_label::String()) },
_domain { node.attribute_value("domain", Domain_name()) }
{ }
/************
** Uplink **
************/
void Uplink::_invalid(char const *reason) const
{
if (_config.verbose()) {
log("[", domain(), "] invalid uplink: ", *this, " (", reason, ")"); }
throw Invalid();
}
Net::Uplink::Uplink(Xml_node const &node,
Allocator &alloc,
Uplink_tree &old_uplinks,
Env &env,
Timer::Connection &timer,
Interface_list &interfaces,
Configuration &config)
:
Uplink_base { node },
Avl_string_base { label().string() },
_alloc { alloc },
_config { config }
{
/* if an interface with this label already exists, reuse it */
try {
Uplink &old_uplink = old_uplinks.find_by_name(label());
Uplink_interface &interface = old_uplink._interface();
old_uplink._interface = Pointer<Uplink_interface>();
interface.domain_name(domain());
_interface = interface;
}
/* if not, create a new one */
catch (Uplink_tree::No_match) {
if (config.verbose()) {
log("[", domain(), "] request uplink NIC session: ", *this); }
try {
_interface = *new (_alloc)
Uplink_interface { env, timer, alloc, interfaces, config,
domain(), label() };
}
catch (Insufficient_ram_quota) { _invalid("NIC session RAM quota"); }
catch (Insufficient_cap_quota) { _invalid("NIC session CAP quota"); }
catch (Service_denied) { _invalid("NIC session denied"); }
}
}
Net::Uplink::~Uplink()
{
/* if the interface was yet not reused by another uplink, destroy it */
try {
Uplink_interface &interface = _interface();
if (_config.verbose()) {
log("[", domain(), "] close uplink NIC session: ", *this); }
destroy(_alloc, &interface);
}
catch (Pointer<Uplink_interface>::Invalid) { }
}
void Net::Uplink::print(Output &output) const
{
if (label() == Session_label()) {
Genode::print(output, "<unlabeled>"); }
else {
Genode::print(output, label()); }
}
/**********************
** Uplink_interface **
**********************/
Net::Uplink_interface::Uplink_interface(Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Domain_name const &domain_name,
Session_label const &label)
:
Uplink_interface_base { domain_name },
Nic::Packet_allocator { &alloc },
Nic::Connection { env, this, BUF_SIZE, BUF_SIZE, label.string() },
_label { label },
_link_state_handler { env.ep(), *this, &Uplink::_handle_link_state },
_link_state_handler { env.ep(), *this,
&Uplink_interface::_handle_link_state },
_interface { env.ep(), timer, mac_address(), alloc,
Mac_address(), config, interfaces, *rx(), *tx(),
_link_state, _intf_policy }
_link_state, *this }
{
/* install packet stream signal handlers */
rx_channel()->sigh_ready_to_ack (_interface.sink_ack());
@ -50,9 +140,8 @@ Net::Uplink::Uplink(Env &env,
}
void Net::Uplink::_handle_link_state()
void Net::Uplink_interface::_handle_link_state()
{
_link_state = link_state();
try { _interface.domain().discard_ip_config(); }
catch (Domain::Ip_config_static) { }
_interface.handle_link_state();
}

View File

@ -19,6 +19,7 @@
#include <nic/packet_allocator.h>
/* local includes */
#include <avl_string_tree.h>
#include <interface.h>
#include <ipv4_address_prefix.h>
@ -27,32 +28,110 @@ namespace Net {
using Domain_name = Genode::String<160>;
class Uplink_base;
class Uplink;
class Uplink_tree;
class Uplink_interface_base;
class Uplink_interface;
}
class Net::Uplink_tree
:
public Avl_string_tree<Uplink, Genode::Session_label>
{ };
class Net::Uplink_base
{
protected:
private:
struct Interface_policy : Net::Interface_policy
{
/***************************
** Net::Interface_policy **
***************************/
Genode::Session_label const _label;
Domain_name const _domain;
Domain_name determine_domain_name() const override { return Genode::Cstring("uplink"); };
void handle_config(Configuration const &) override { }
};
public:
Interface_policy _intf_policy { };
Uplink_base(Genode::Xml_node const &node);
virtual ~Uplink_base() { }
/**************
** Acessors **
**************/
Genode::Session_label const &label() const { return _label; }
Domain_name const &domain() const { return _domain; }
};
class Net::Uplink : public Uplink_base,
public Nic::Packet_allocator,
public Nic::Connection
struct Net::Uplink : public Uplink_base,
private Genode::Avl_string_base
{
friend class Avl_string_tree<Uplink, Genode::Session_label>;
friend class Genode::List<Uplink>;
private:
Genode::Allocator &_alloc;
Configuration const &_config;
Pointer<Uplink_interface> _interface { };
void _invalid(char const *reason) const;
public:
struct Invalid : Genode::Exception { };
Uplink(Genode::Xml_node const &node,
Genode::Allocator &alloc,
Uplink_tree &old_uplinks,
Genode::Env &env,
Timer::Connection &timer,
Interface_list &interfaces,
Configuration &config);
~Uplink();
/*********
** log **
*********/
void print(Genode::Output &output) const;
};
class Net::Uplink_interface_base : public Interface_policy
{
private:
Const_reference<Domain_name> _domain_name;
/***************************
** Net::Interface_policy **
***************************/
Domain_name determine_domain_name() const override { return _domain_name(); };
void handle_config(Configuration const &) override { }
public:
Uplink_interface_base(Domain_name const &domain_name) : _domain_name(domain_name) { }
virtual ~Uplink_interface_base() { }
/***************
** Accessors **
***************/
void domain_name(Domain_name const &v) { _domain_name = v; }
};
class Net::Uplink_interface : public Uplink_interface_base,
public Nic::Packet_allocator,
public Nic::Connection
{
private:
@ -61,10 +140,9 @@ class Net::Uplink : public Uplink_base,
BUF_SIZE = Nic::Session::QUEUE_SIZE * PKT_SIZE,
};
Genode::Session_label const &_label;
bool _link_state { false };
Genode::Signal_handler<Uplink> _link_state_handler;
Net::Interface _interface;
bool _link_state { false };
Genode::Signal_handler<Uplink_interface> _link_state_handler;
Net::Interface _interface;
Ipv4_address_prefix _read_interface();
@ -72,20 +150,20 @@ class Net::Uplink : public Uplink_base,
public:
Uplink(Genode::Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Genode::Session_label const &label);
Uplink_interface(Genode::Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Interface_list &interfaces,
Configuration &config,
Domain_name const &domain_name,
Genode::Session_label const &label);
/***************
** Accessors **
***************/
Mac_address const &router_mac() const { return _interface.router_mac(); }
Genode::Session_label const &label() const { return _label; }
Mac_address const &router_mac() const { return _interface.router_mac(); }
};
#endif /* _UPLINK_H_ */

View File

@ -23,6 +23,7 @@
<provides> <service name="Nic"/> </provides>
<config verbose_domain_state="yes">
<default-policy domain="default" />
<uplink domain="uplink" />
<domain name="uplink">
<nat domain="default" tcp-ports="1000" udp-ports="1000"/>
</domain>

View File

@ -149,6 +149,7 @@ append_if $use_nic_router config {
<config verbose_domain_state="yes">
<policy label_prefix="netserver_genode" domain="server"/>
<uplink domain="uplink"/>
<domain name="uplink"}
append_if [expr $use_nic_router && [have_spec linux]] config "

View File

@ -64,8 +64,10 @@ append config {
<resource name="RAM" quantum="10M"/>
<provides><service name="Nic"/></provides>
<config verbose="no">
<policy label_prefix="vfs" domain="default" />
<policy label_prefix="stubby" domain="dns"/>
<policy label_prefix="vfs" domain="default" />
<policy label_prefix="stubby" domain="dns" />
<uplink domain="uplink" />
<domain name="uplink">
<nat domain="dns" tcp-ports="64" udp-ports="64"/>
</domain>

View File

@ -159,6 +159,7 @@ append config {
dhcp_discover_timeout_sec="1">
<policy label_prefix="vbox" domain="downlink"/>
<uplink domain="uplink" />
<domain name="uplink" label="wifi">
<nat domain="downlink"