mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
nic_router: support interfaces without a domain
Clients can connect at any time to the NIC router. The interfaces (sessions) get attached to the appropriate domain as soon as it appears. This implies that interfaces can also be detached from a domain without beeing destructed when the domain disappears. All user dependent states of an interface such as the link states, DHCP allocations and ARP information get lost when the interface gets detached. Ref #2670
This commit is contained in:
parent
63de13b50e
commit
2c2037952d
@ -38,43 +38,70 @@ Communication_buffer::Communication_buffer(Ram_session &ram,
|
||||
****************************/
|
||||
|
||||
Session_component_base::
|
||||
Session_component_base(Allocator &guarded_alloc_backing,
|
||||
size_t const guarded_alloc_amount,
|
||||
Ram_session &buf_ram,
|
||||
size_t const tx_buf_size,
|
||||
size_t const rx_buf_size)
|
||||
Session_component_base(Allocator &guarded_alloc_backing,
|
||||
size_t const guarded_alloc_amount,
|
||||
Ram_session &buf_ram,
|
||||
size_t const tx_buf_size,
|
||||
size_t const rx_buf_size,
|
||||
Configuration const &config,
|
||||
Session_label const &label)
|
||||
:
|
||||
_guarded_alloc(&guarded_alloc_backing, guarded_alloc_amount),
|
||||
_range_alloc(&_guarded_alloc), _tx_buf(buf_ram, tx_buf_size),
|
||||
_rx_buf(buf_ram, rx_buf_size)
|
||||
_rx_buf(buf_ram, rx_buf_size), _intf_policy(label, config)
|
||||
{ }
|
||||
|
||||
|
||||
/**********************************************
|
||||
** Session_component_base::Interface_policy **
|
||||
**********************************************/
|
||||
|
||||
Net::Session_component_base::
|
||||
Interface_policy::Interface_policy(Genode::Session_label const &label,
|
||||
Configuration const &config)
|
||||
: label(label), config(config) { }
|
||||
|
||||
|
||||
Domain_name
|
||||
Net::Session_component_base::Interface_policy::determine_domain_name() const
|
||||
{
|
||||
Domain_name domain_name;
|
||||
try {
|
||||
Session_policy policy(label, config.node());
|
||||
domain_name = policy.attribute_value("domain", Domain_name());
|
||||
}
|
||||
catch (Session_policy::No_policy_defined) { if (config.verbose()) { log("No matching policy"); } }
|
||||
catch (Xml_node::Nonexistent_attribute) { if (config.verbose()) { log("No domain attribute in policy"); } }
|
||||
return domain_name;
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** Session_component **
|
||||
***********************/
|
||||
|
||||
Net::Session_component::Session_component(Allocator &alloc,
|
||||
Timer::Connection &timer,
|
||||
size_t const amount,
|
||||
Ram_session &buf_ram,
|
||||
size_t const tx_buf_size,
|
||||
size_t const rx_buf_size,
|
||||
Region_map ®ion_map,
|
||||
Mac_address const mac,
|
||||
Entrypoint &ep,
|
||||
Mac_address const &router_mac,
|
||||
Domain &domain)
|
||||
Net::Session_component::Session_component(Allocator &alloc,
|
||||
Timer::Connection &timer,
|
||||
size_t const amount,
|
||||
Ram_session &buf_ram,
|
||||
size_t const tx_buf_size,
|
||||
size_t const rx_buf_size,
|
||||
Region_map ®ion_map,
|
||||
Mac_address const mac,
|
||||
Entrypoint &ep,
|
||||
Mac_address const &router_mac,
|
||||
Session_label const &label,
|
||||
Configuration &config)
|
||||
:
|
||||
Session_component_base(alloc, amount, buf_ram, tx_buf_size, rx_buf_size),
|
||||
Session_component_base(alloc, amount, buf_ram, tx_buf_size, rx_buf_size,
|
||||
config, label),
|
||||
Session_rpc_object(region_map, _tx_buf, _rx_buf, &_range_alloc, ep.rpc_ep()),
|
||||
Interface(ep, timer, router_mac, _guarded_alloc, mac, domain)
|
||||
Interface(ep, timer, router_mac, _guarded_alloc, mac, config, _intf_policy)
|
||||
{
|
||||
_tx.sigh_ready_to_ack(_sink_ack);
|
||||
_tx.sigh_packet_avail(_sink_submit);
|
||||
_rx.sigh_ack_avail(_source_ack);
|
||||
_rx.sigh_ready_to_submit(_source_submit);
|
||||
Interface::_init();
|
||||
}
|
||||
|
||||
|
||||
@ -99,12 +126,6 @@ Net::Root::Root(Entrypoint &ep,
|
||||
Session_component *Net::Root::_create_session(char const *args)
|
||||
{
|
||||
try {
|
||||
Session_label const label = label_from_args(args);
|
||||
Session_policy policy(label, _config.node());
|
||||
Domain_name domain_name(policy.attribute_value("domain", Domain_name()));
|
||||
|
||||
Domain &domain = _config.domains().find_by_name(domain_name);
|
||||
|
||||
size_t const ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
||||
|
||||
@ -127,23 +148,15 @@ Session_component *Net::Root::_create_session(char const *args)
|
||||
error("insufficient 'ram_quota' for session creation");
|
||||
throw Insufficient_ram_quota();
|
||||
}
|
||||
Session_label const label(label_from_args(args));
|
||||
return new (md_alloc())
|
||||
Session_component(*md_alloc(), _timer, ram_quota - session_size,
|
||||
_buf_ram, tx_buf_size, rx_buf_size, _region_map,
|
||||
_mac_alloc.alloc(), _ep, _router_mac,
|
||||
domain);
|
||||
}
|
||||
catch (Session_policy::No_policy_defined) {
|
||||
error("no matching policy");
|
||||
}
|
||||
catch (Domain_tree::No_match) {
|
||||
error("no matching domain");
|
||||
_mac_alloc.alloc(), _ep, _router_mac, label,
|
||||
_config);
|
||||
}
|
||||
catch (Mac_allocator::Alloc_failed) {
|
||||
error("failed to allocate MAC address");
|
||||
}
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
error("missing domain attribute in policy");
|
||||
}
|
||||
throw Service_denied();
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
namespace Net {
|
||||
|
||||
class Domain;
|
||||
class Communication_buffer;
|
||||
class Session_component_base;
|
||||
class Session_component;
|
||||
@ -53,18 +52,37 @@ class Net::Session_component_base
|
||||
{
|
||||
protected:
|
||||
|
||||
struct Interface_policy : Net::Interface_policy
|
||||
{
|
||||
Genode::Session_label const label;
|
||||
Configuration const &config;
|
||||
|
||||
Interface_policy(Genode::Session_label const &label,
|
||||
Configuration const &config);
|
||||
|
||||
|
||||
/***************************
|
||||
** Net::Interface_policy **
|
||||
***************************/
|
||||
|
||||
Domain_name determine_domain_name() const override;
|
||||
};
|
||||
|
||||
Genode::Allocator_guard _guarded_alloc;
|
||||
Nic::Packet_allocator _range_alloc;
|
||||
Communication_buffer _tx_buf;
|
||||
Communication_buffer _rx_buf;
|
||||
Interface_policy _intf_policy;
|
||||
|
||||
public:
|
||||
|
||||
Session_component_base(Genode::Allocator &guarded_alloc_backing,
|
||||
Genode::size_t const guarded_alloc_amount,
|
||||
Genode::Ram_session &buf_ram,
|
||||
Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size);
|
||||
Session_component_base(Genode::Allocator &guarded_alloc_backing,
|
||||
Genode::size_t const guarded_alloc_amount,
|
||||
Genode::Ram_session &buf_ram,
|
||||
Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Configuration const &config,
|
||||
Genode::Session_label const &label);
|
||||
};
|
||||
|
||||
|
||||
@ -83,17 +101,18 @@ class Net::Session_component : private Session_component_base,
|
||||
|
||||
public:
|
||||
|
||||
Session_component(Genode::Allocator &alloc,
|
||||
Timer::Connection &timer,
|
||||
Genode::size_t const amount,
|
||||
Genode::Ram_session &buf_ram,
|
||||
Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Region_map ®ion_map,
|
||||
Mac_address const mac,
|
||||
Genode::Entrypoint &ep,
|
||||
Mac_address const &router_mac,
|
||||
Domain &domain);
|
||||
Session_component(Genode::Allocator &alloc,
|
||||
Timer::Connection &timer,
|
||||
Genode::size_t const amount,
|
||||
Genode::Ram_session &buf_ram,
|
||||
Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Region_map ®ion_map,
|
||||
Mac_address const mac,
|
||||
Genode::Entrypoint &ep,
|
||||
Mac_address const &router_mac,
|
||||
Genode::Session_label const &label,
|
||||
Configuration &config);
|
||||
|
||||
|
||||
/******************
|
||||
|
@ -42,6 +42,7 @@ class Net::Configuration
|
||||
Genode::Microseconds const _tcp_max_segm_lifetime;
|
||||
Pointer<Report> _report { };
|
||||
Domain_tree _domains { };
|
||||
List<Interface> _detached_interfaces { };
|
||||
Genode::Xml_node const _node;
|
||||
|
||||
public:
|
||||
@ -74,6 +75,7 @@ class Net::Configuration
|
||||
Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; }
|
||||
Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; }
|
||||
Domain_tree &domains() { return _domains; }
|
||||
List<Interface> &detached_interfaces() { return _detached_interfaces; }
|
||||
Report &report() { return _report.deref(); }
|
||||
Genode::Xml_node node() const { return _node; }
|
||||
};
|
||||
|
@ -217,7 +217,7 @@ Ipv4_address const &Domain::next_hop(Ipv4_address const &ip) const
|
||||
}
|
||||
|
||||
|
||||
void Domain::manage_interface(Interface &interface)
|
||||
void Domain::attach_interface(Interface &interface)
|
||||
{
|
||||
_interfaces.insert(&interface);
|
||||
_interface_cnt++;
|
||||
@ -227,7 +227,7 @@ void Domain::manage_interface(Interface &interface)
|
||||
}
|
||||
|
||||
|
||||
void Domain::dissolve_interface(Interface &interface)
|
||||
void Domain::detach_interface(Interface &interface)
|
||||
{
|
||||
_interfaces.remove(&interface);
|
||||
_interface_cnt--;
|
||||
|
@ -143,9 +143,9 @@ class Net::Domain : public Domain_base
|
||||
|
||||
Link_side_tree &links(L3_protocol const protocol);
|
||||
|
||||
void manage_interface(Interface &interface);
|
||||
void attach_interface(Interface &interface);
|
||||
|
||||
void dissolve_interface(Interface &interface);
|
||||
void detach_interface(Interface &interface);
|
||||
|
||||
void raise_rx_bytes(Genode::size_t bytes) { _rx_bytes += bytes; }
|
||||
|
||||
|
@ -175,25 +175,42 @@ void Interface::_pass_ip(Ethernet_frame ð,
|
||||
|
||||
|
||||
Forward_rule_tree &
|
||||
Interface::_forward_rules(L3_protocol const prot) const
|
||||
Interface::_forward_rules(Domain &local_domain, L3_protocol const prot) const
|
||||
{
|
||||
switch (prot) {
|
||||
case L3_protocol::TCP: return _domain.tcp_forward_rules();
|
||||
case L3_protocol::UDP: return _domain.udp_forward_rules();
|
||||
case L3_protocol::TCP: return local_domain.tcp_forward_rules();
|
||||
case L3_protocol::UDP: return local_domain.udp_forward_rules();
|
||||
default: throw Bad_transport_protocol(); }
|
||||
}
|
||||
|
||||
|
||||
Transport_rule_list &
|
||||
Interface::_transport_rules(L3_protocol const prot) const
|
||||
Interface::_transport_rules(Domain &local_domain, L3_protocol const prot) const
|
||||
{
|
||||
switch (prot) {
|
||||
case L3_protocol::TCP: return _domain.tcp_rules();
|
||||
case L3_protocol::UDP: return _domain.udp_rules();
|
||||
case L3_protocol::TCP: return local_domain.tcp_rules();
|
||||
case L3_protocol::UDP: return local_domain.udp_rules();
|
||||
default: throw Bad_transport_protocol(); }
|
||||
}
|
||||
|
||||
|
||||
void Interface::attach_to_domain(Domain &domain)
|
||||
{
|
||||
_domain_ptr.set(domain);
|
||||
domain.attach_interface(*this);
|
||||
if (!domain.ip_config().valid) {
|
||||
_dhcp_client.discover();
|
||||
}
|
||||
}
|
||||
|
||||
struct Detach_from_domain_not_implemented : Genode::Exception { };
|
||||
void Interface::detach_from_domain()
|
||||
{
|
||||
_domain_ptr.unset();
|
||||
throw Detach_from_domain_not_implemented();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Interface::_new_link(L3_protocol const protocol,
|
||||
Link_side_id const &local,
|
||||
@ -204,11 +221,11 @@ Interface::_new_link(L3_protocol const protocol,
|
||||
switch (protocol) {
|
||||
case L3_protocol::TCP:
|
||||
new (_alloc) Tcp_link(*this, local, remote_port_alloc, remote_domain,
|
||||
remote, _timer, _config(), protocol);
|
||||
remote, _timer, _config, protocol);
|
||||
break;
|
||||
case L3_protocol::UDP:
|
||||
new (_alloc) Udp_link(*this, local, remote_port_alloc, remote_domain,
|
||||
remote, _timer, _config(), protocol);
|
||||
remote, _timer, _config, protocol);
|
||||
break;
|
||||
default: throw Bad_transport_protocol(); }
|
||||
}
|
||||
@ -216,7 +233,7 @@ Interface::_new_link(L3_protocol const protocol,
|
||||
|
||||
void Interface::dhcp_allocation_expired(Dhcp_allocation &allocation)
|
||||
{
|
||||
_release_dhcp_allocation(allocation);
|
||||
_release_dhcp_allocation(allocation, _domain_ptr.deref());
|
||||
_released_dhcp_allocations.insert(&allocation);
|
||||
}
|
||||
|
||||
@ -240,21 +257,22 @@ Link_list &Interface::dissolved_links(L3_protocol const protocol)
|
||||
|
||||
|
||||
void Interface::_adapt_eth(Ethernet_frame ð,
|
||||
size_t ,
|
||||
Ipv4_address const &ip,
|
||||
Ipv4_address const &dst_ip,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &domain)
|
||||
Domain &remote_domain)
|
||||
{
|
||||
if (!domain.ip_config().valid) {
|
||||
Ipv4_config const &remote_ip_cfg = remote_domain.ip_config();
|
||||
if (!remote_ip_cfg.valid) {
|
||||
throw Drop_packet_inform("target domain has yet no IP config");
|
||||
}
|
||||
Ipv4_address const &hop_ip = domain.next_hop(ip);
|
||||
try { eth.dst(domain.arp_cache().find_by_ip(hop_ip).mac()); }
|
||||
Ipv4_address const &hop_ip = remote_domain.next_hop(dst_ip);
|
||||
try { eth.dst(remote_domain.arp_cache().find_by_ip(hop_ip).mac()); }
|
||||
catch (Arp_cache::No_match) {
|
||||
domain.interfaces().for_each([&] (Interface &interface) {
|
||||
interface._broadcast_arp_request(hop_ip);
|
||||
remote_domain.interfaces().for_each([&] (Interface &interface) {
|
||||
interface._broadcast_arp_request(remote_ip_cfg.interface.address,
|
||||
hop_ip);
|
||||
});
|
||||
new (_alloc) Arp_waiter(*this, domain, hop_ip, pkt);
|
||||
new (_alloc) Arp_waiter(*this, remote_domain, hop_ip, pkt);
|
||||
throw Packet_postponed();
|
||||
}
|
||||
eth.src(_router_mac);
|
||||
@ -267,24 +285,25 @@ void Interface::_nat_link_and_pass(Ethernet_frame ð,
|
||||
L3_protocol const prot,
|
||||
void *const prot_base,
|
||||
size_t const prot_size,
|
||||
Link_side_id const &local,
|
||||
Domain &domain)
|
||||
Link_side_id const &local_id,
|
||||
Domain &local_domain,
|
||||
Domain &remote_domain)
|
||||
{
|
||||
Pointer<Port_allocator_guard> remote_port_alloc;
|
||||
try {
|
||||
Nat_rule &nat = domain.nat_rules().find_by_domain(_domain);
|
||||
if(_config().verbose()) {
|
||||
Nat_rule &nat = remote_domain.nat_rules().find_by_domain(local_domain);
|
||||
if(_config.verbose()) {
|
||||
log("Using NAT rule: ", nat); }
|
||||
|
||||
_src_port(prot, prot_base, nat.port_alloc(prot).alloc());
|
||||
ip.src(domain.ip_config().interface.address);
|
||||
ip.src(remote_domain.ip_config().interface.address);
|
||||
remote_port_alloc.set(nat.port_alloc(prot));
|
||||
}
|
||||
catch (Nat_rule_tree::No_match) { }
|
||||
Link_side_id const remote = { ip.dst(), _dst_port(prot, prot_base),
|
||||
ip.src(), _src_port(prot, prot_base) };
|
||||
_new_link(prot, local, remote_port_alloc, domain, remote);
|
||||
domain.interfaces().for_each([&] (Interface &interface) {
|
||||
Link_side_id const remote_id = { ip.dst(), _dst_port(prot, prot_base),
|
||||
ip.src(), _src_port(prot, prot_base) };
|
||||
_new_link(prot, local_id, remote_port_alloc, remote_domain, remote_id);
|
||||
remote_domain.interfaces().for_each([&] (Interface &interface) {
|
||||
interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size);
|
||||
});
|
||||
}
|
||||
@ -294,7 +313,8 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
Mac_address const &client_mac,
|
||||
Ipv4_address const &client_ip,
|
||||
Dhcp_packet::Message_type msg_type,
|
||||
uint32_t xid)
|
||||
uint32_t xid,
|
||||
Ipv4_address_prefix const &local_intf)
|
||||
{
|
||||
enum { PKT_SIZE = 512 };
|
||||
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Dhcp_msg_buffer_too_small>;
|
||||
@ -321,7 +341,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
ip.fragment_offset(0);
|
||||
ip.time_to_live(IPV4_TIME_TO_LIVE);
|
||||
ip.protocol(Ipv4_packet::Protocol::UDP);
|
||||
ip.src(_router_ip());
|
||||
ip.src(local_intf.address);
|
||||
ip.dst(client_ip);
|
||||
|
||||
/* create UDP header of the reply */
|
||||
@ -343,7 +363,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
dhcp.flags(0);
|
||||
dhcp.ciaddr(msg_type == Dhcp_packet::Message_type::INFORM ? client_ip : Ipv4_address());
|
||||
dhcp.yiaddr(msg_type == Dhcp_packet::Message_type::INFORM ? Ipv4_address() : client_ip);
|
||||
dhcp.siaddr(_router_ip());
|
||||
dhcp.siaddr(local_intf.address);
|
||||
dhcp.giaddr(Ipv4_address());
|
||||
dhcp.client_mac(client_mac);
|
||||
dhcp.zero_fill_sname();
|
||||
@ -353,13 +373,13 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
/* append DHCP option fields to the reply */
|
||||
Dhcp_packet::Options_aggregator<Size_guard> dhcp_opts(dhcp, size);
|
||||
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
||||
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(_router_ip());
|
||||
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(local_intf.address);
|
||||
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
|
||||
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(_ip_config().interface.subnet_mask());
|
||||
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(_router_ip());
|
||||
dhcp_opts.append_option<Dhcp_packet::Subnet_mask>(local_intf.subnet_mask());
|
||||
dhcp_opts.append_option<Dhcp_packet::Router_ipv4>(local_intf.address);
|
||||
if (dhcp_srv.dns_server().valid()) {
|
||||
dhcp_opts.append_option<Dhcp_packet::Dns_server_ipv4>(dhcp_srv.dns_server()); }
|
||||
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(_ip_config().interface.broadcast_address());
|
||||
dhcp_opts.append_option<Dhcp_packet::Broadcast_addr>(local_intf.broadcast_address());
|
||||
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
||||
|
||||
/* fill in header values that need the packet to be complete already */
|
||||
@ -371,10 +391,12 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
}
|
||||
|
||||
|
||||
void Interface::_release_dhcp_allocation(Dhcp_allocation &allocation)
|
||||
void Interface::_release_dhcp_allocation(Dhcp_allocation &allocation,
|
||||
Domain &local_domain)
|
||||
{
|
||||
if (_config().verbose()) {
|
||||
log("Release DHCP allocation: ", allocation, " at ", _domain);
|
||||
if (_config.verbose()) {
|
||||
log("Release DHCP allocation: ", allocation,
|
||||
" at ", local_domain);
|
||||
}
|
||||
_dhcp_allocations.remove(&allocation);
|
||||
}
|
||||
@ -382,32 +404,35 @@ void Interface::_release_dhcp_allocation(Dhcp_allocation &allocation)
|
||||
|
||||
void Interface::_new_dhcp_allocation(Ethernet_frame ð,
|
||||
Dhcp_packet &dhcp,
|
||||
Dhcp_server &dhcp_srv)
|
||||
Dhcp_server &dhcp_srv,
|
||||
Domain &local_domain)
|
||||
{
|
||||
Dhcp_allocation &allocation = *new (_alloc)
|
||||
Dhcp_allocation(*this, dhcp_srv.alloc_ip(),
|
||||
dhcp.client_mac(), _timer,
|
||||
_config().dhcp_offer_timeout());
|
||||
_config.dhcp_offer_timeout());
|
||||
|
||||
_dhcp_allocations.insert(&allocation);
|
||||
if (_config().verbose()) {
|
||||
if (_config.verbose()) {
|
||||
log("Offer DHCP allocation: ", allocation,
|
||||
" at ", _domain);
|
||||
" at ", local_domain);
|
||||
}
|
||||
_send_dhcp_reply(dhcp_srv, eth.src(),
|
||||
allocation.ip(),
|
||||
Dhcp_packet::Message_type::OFFER,
|
||||
dhcp.xid());
|
||||
dhcp.xid(),
|
||||
local_domain.ip_config().interface);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void Interface::_handle_dhcp_request(Ethernet_frame ð, size_t ,
|
||||
Dhcp_packet &dhcp)
|
||||
Dhcp_packet &dhcp,
|
||||
Domain &local_domain)
|
||||
{
|
||||
try {
|
||||
/* try to get the DHCP server config of this interface */
|
||||
Dhcp_server &dhcp_srv = _domain.dhcp_server();
|
||||
Dhcp_server &dhcp_srv = local_domain.dhcp_server();
|
||||
|
||||
/* determine type of DHCP request */
|
||||
Dhcp_packet::Message_type const msg_type =
|
||||
@ -418,22 +443,25 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, size_t ,
|
||||
Dhcp_allocation &allocation =
|
||||
_dhcp_allocations.find_by_mac(dhcp.client_mac());
|
||||
|
||||
Ipv4_address_prefix const &local_intf =
|
||||
local_domain.ip_config().interface;
|
||||
|
||||
switch (msg_type) {
|
||||
case Dhcp_packet::Message_type::DISCOVER:
|
||||
|
||||
if (allocation.bound()) {
|
||||
|
||||
_release_dhcp_allocation(allocation);
|
||||
_destroy_dhcp_allocation(allocation);
|
||||
_new_dhcp_allocation(eth, dhcp, dhcp_srv);
|
||||
_release_dhcp_allocation(allocation, local_domain);
|
||||
_destroy_dhcp_allocation(allocation, local_domain);
|
||||
_new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain);
|
||||
return;
|
||||
|
||||
} else {
|
||||
allocation.lifetime(_config().dhcp_offer_timeout());
|
||||
allocation.lifetime(_config.dhcp_offer_timeout());
|
||||
_send_dhcp_reply(dhcp_srv, eth.src(),
|
||||
allocation.ip(),
|
||||
Dhcp_packet::Message_type::OFFER,
|
||||
dhcp.xid());
|
||||
dhcp.xid(), local_intf);
|
||||
return;
|
||||
}
|
||||
case Dhcp_packet::Message_type::REQUEST:
|
||||
@ -443,31 +471,31 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, size_t ,
|
||||
_send_dhcp_reply(dhcp_srv, eth.src(),
|
||||
allocation.ip(),
|
||||
Dhcp_packet::Message_type::ACK,
|
||||
dhcp.xid());
|
||||
dhcp.xid(), local_intf);
|
||||
return;
|
||||
|
||||
} else {
|
||||
Dhcp_packet::Server_ipv4 &dhcp_srv_ip =
|
||||
dhcp.option<Dhcp_packet::Server_ipv4>();
|
||||
|
||||
if (dhcp_srv_ip.value() == _router_ip()) {
|
||||
|
||||
if (dhcp_srv_ip.value() == local_intf.address)
|
||||
{
|
||||
allocation.set_bound();
|
||||
allocation.lifetime(dhcp_srv.ip_lease_time());
|
||||
if (_config().verbose()) {
|
||||
if (_config.verbose()) {
|
||||
log("Bind DHCP allocation: ", allocation,
|
||||
" at ", _domain);
|
||||
" at ", local_domain);
|
||||
}
|
||||
_send_dhcp_reply(dhcp_srv, eth.src(),
|
||||
allocation.ip(),
|
||||
Dhcp_packet::Message_type::ACK,
|
||||
dhcp.xid());
|
||||
dhcp.xid(), local_intf);
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
_release_dhcp_allocation(allocation);
|
||||
_destroy_dhcp_allocation(allocation);
|
||||
_release_dhcp_allocation(allocation, local_domain);
|
||||
_destroy_dhcp_allocation(allocation, local_domain);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -476,14 +504,14 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, size_t ,
|
||||
_send_dhcp_reply(dhcp_srv, eth.src(),
|
||||
allocation.ip(),
|
||||
Dhcp_packet::Message_type::ACK,
|
||||
dhcp.xid());
|
||||
dhcp.xid(), local_intf);
|
||||
return;
|
||||
|
||||
case Dhcp_packet::Message_type::DECLINE:
|
||||
case Dhcp_packet::Message_type::RELEASE:
|
||||
|
||||
_release_dhcp_allocation(allocation);
|
||||
_destroy_dhcp_allocation(allocation);
|
||||
_release_dhcp_allocation(allocation, local_domain);
|
||||
_destroy_dhcp_allocation(allocation, local_domain);
|
||||
return;
|
||||
|
||||
case Dhcp_packet::Message_type::NAK: throw Drop_packet_warn("DHCP NAK from client");
|
||||
@ -497,7 +525,7 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, size_t ,
|
||||
switch (msg_type) {
|
||||
case Dhcp_packet::Message_type::DISCOVER:
|
||||
|
||||
_new_dhcp_allocation(eth, dhcp, dhcp_srv);
|
||||
_new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain);
|
||||
return;
|
||||
|
||||
case Dhcp_packet::Message_type::REQUEST: throw Drop_packet_warn("DHCP REQUEST from client without offered/acked IP");
|
||||
@ -518,10 +546,12 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, size_t ,
|
||||
}
|
||||
|
||||
|
||||
void Interface::_domain_broadcast(Ethernet_frame ð, size_t eth_size)
|
||||
void Interface::_domain_broadcast(Ethernet_frame ð,
|
||||
size_t eth_size,
|
||||
Domain &local_domain)
|
||||
{
|
||||
eth.src(_router_mac);
|
||||
_domain.interfaces().for_each([&] (Interface &interface) {
|
||||
local_domain.interfaces().for_each([&] (Interface &interface) {
|
||||
if (&interface != this) {
|
||||
interface.send(eth, eth_size);
|
||||
}
|
||||
@ -531,20 +561,22 @@ void Interface::_domain_broadcast(Ethernet_frame ð, size_t eth_size)
|
||||
|
||||
void Interface::_handle_ip(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
Packet_descriptor const &pkt)
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain)
|
||||
{
|
||||
/* read packet information */
|
||||
Ipv4_packet &ip = *eth.data<Ipv4_packet>(eth_size - sizeof(Ethernet_frame));
|
||||
Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface;
|
||||
|
||||
/* try handling subnet-local IP packets */
|
||||
if (_ip_config().interface.prefix_matches(ip.dst()) &&
|
||||
ip.dst() != _router_ip())
|
||||
if (local_intf.prefix_matches(ip.dst()) &&
|
||||
ip.dst() != local_intf.address)
|
||||
{
|
||||
/*
|
||||
* Packet targets IP local to the domain's subnet and doesn't target
|
||||
* the router. Thus, forward it to all other interfaces of the domain.
|
||||
*/
|
||||
_domain_broadcast(eth, eth_size);
|
||||
_domain_broadcast(eth, eth_size, local_domain);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -566,7 +598,7 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
|
||||
if (dhcp.op() == Dhcp_packet::REQUEST) {
|
||||
try {
|
||||
_handle_dhcp_request(eth, eth_size, dhcp);
|
||||
_handle_dhcp_request(eth, eth_size, dhcp, local_domain);
|
||||
return;
|
||||
}
|
||||
catch (Pointer<Dhcp_server>::Invalid) { }
|
||||
@ -576,26 +608,26 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
}
|
||||
}
|
||||
}
|
||||
Link_side_id const local = { ip.src(), _src_port(prot, prot_base),
|
||||
ip.dst(), _dst_port(prot, prot_base) };
|
||||
Link_side_id const local_id = { ip.src(), _src_port(prot, prot_base),
|
||||
ip.dst(), _dst_port(prot, prot_base) };
|
||||
|
||||
/* try to route via existing UDP/TCP links */
|
||||
try {
|
||||
Link_side const &local_side = _domain.links(prot).find_by_id(local);
|
||||
Link_side const &local_side = local_domain.links(prot).find_by_id(local_id);
|
||||
Link &link = local_side.link();
|
||||
bool const client = local_side.is_client();
|
||||
Link_side &remote_side = client ? link.server() : link.client();
|
||||
Domain &domain = remote_side.domain();
|
||||
if (_config().verbose()) {
|
||||
Domain &remote_domain = remote_side.domain();
|
||||
if (_config.verbose()) {
|
||||
log("Using ", l3_protocol_name(prot), " link: ", link); }
|
||||
|
||||
_adapt_eth(eth, eth_size, remote_side.src_ip(), pkt, domain);
|
||||
_adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain);
|
||||
ip.src(remote_side.dst_ip());
|
||||
ip.dst(remote_side.src_ip());
|
||||
_src_port(prot, prot_base, remote_side.dst_port());
|
||||
_dst_port(prot, prot_base, remote_side.src_port());
|
||||
|
||||
domain.interfaces().for_each([&] (Interface &interface) {
|
||||
remote_domain.interfaces().for_each([&] (Interface &interface) {
|
||||
interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size);
|
||||
});
|
||||
_link_packet(prot, prot_base, link, client);
|
||||
@ -604,19 +636,19 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
catch (Link_side_tree::No_match) { }
|
||||
|
||||
/* try to route via forward rules */
|
||||
if (local.dst_ip == _router_ip()) {
|
||||
if (local_id.dst_ip == local_intf.address) {
|
||||
try {
|
||||
Forward_rule const &rule =
|
||||
_forward_rules(prot).find_by_port(local.dst_port);
|
||||
_forward_rules(local_domain, prot).find_by_port(local_id.dst_port);
|
||||
|
||||
if(_config().verbose()) {
|
||||
if(_config.verbose()) {
|
||||
log("Using forward rule: ", l3_protocol_name(prot), " ", rule); }
|
||||
|
||||
Domain &domain = rule.domain();
|
||||
_adapt_eth(eth, eth_size, rule.to(), pkt, domain);
|
||||
Domain &remote_domain = rule.domain();
|
||||
_adapt_eth(eth, rule.to(), pkt, remote_domain);
|
||||
ip.dst(rule.to());
|
||||
_nat_link_and_pass(eth, eth_size, ip, prot, prot_base,
|
||||
prot_size, local, domain);
|
||||
prot_size, local_id, local_domain, remote_domain);
|
||||
return;
|
||||
}
|
||||
catch (Forward_rule_tree::No_match) { }
|
||||
@ -624,19 +656,19 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
/* try to route via transport and permit rules */
|
||||
try {
|
||||
Transport_rule const &transport_rule =
|
||||
_transport_rules(prot).longest_prefix_match(local.dst_ip);
|
||||
_transport_rules(local_domain, prot).longest_prefix_match(local_id.dst_ip);
|
||||
|
||||
Permit_rule const &permit_rule =
|
||||
transport_rule.permit_rule(local.dst_port);
|
||||
transport_rule.permit_rule(local_id.dst_port);
|
||||
|
||||
if(_config().verbose()) {
|
||||
if(_config.verbose()) {
|
||||
log("Using ", l3_protocol_name(prot), " rule: ", transport_rule,
|
||||
" ", permit_rule); }
|
||||
|
||||
Domain &domain = permit_rule.domain();
|
||||
_adapt_eth(eth, eth_size, local.dst_ip, pkt, domain);
|
||||
Domain &remote_domain = permit_rule.domain();
|
||||
_adapt_eth(eth, local_id.dst_ip, pkt, remote_domain);
|
||||
_nat_link_and_pass(eth, eth_size, ip, prot, prot_base, prot_size,
|
||||
local, domain);
|
||||
local_id, local_domain, remote_domain);
|
||||
return;
|
||||
}
|
||||
catch (Transport_rule_list::No_match) { }
|
||||
@ -647,14 +679,14 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
/* try to route via IP rules */
|
||||
try {
|
||||
Ip_rule const &rule =
|
||||
_domain.ip_rules().longest_prefix_match(ip.dst());
|
||||
local_domain.ip_rules().longest_prefix_match(ip.dst());
|
||||
|
||||
if(_config().verbose()) {
|
||||
if(_config.verbose()) {
|
||||
log("Using IP rule: ", rule); }
|
||||
|
||||
Domain &domain = rule.domain();
|
||||
_adapt_eth(eth, eth_size, ip.dst(), pkt, domain);
|
||||
domain.interfaces().for_each([&] (Interface &interface) {
|
||||
Domain &remote_domain = rule.domain();
|
||||
_adapt_eth(eth, ip.dst(), pkt, remote_domain);
|
||||
remote_domain.interfaces().for_each([&] (Interface &interface) {
|
||||
interface._pass_ip(eth, eth_size, ip);
|
||||
});
|
||||
|
||||
@ -663,12 +695,13 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
catch (Ip_rule_list::No_match) { }
|
||||
|
||||
/* give up and drop packet */
|
||||
if (_config().verbose()) {
|
||||
if (_config.verbose()) {
|
||||
log("Unroutable packet"); }
|
||||
}
|
||||
|
||||
|
||||
void Interface::_broadcast_arp_request(Ipv4_address const &ip)
|
||||
void Interface::_broadcast_arp_request(Ipv4_address const &src_ip,
|
||||
Ipv4_address const &dst_ip)
|
||||
{
|
||||
enum {
|
||||
ETH_HDR_SZ = sizeof(Ethernet_frame),
|
||||
@ -694,31 +727,32 @@ void Interface::_broadcast_arp_request(Ipv4_address const &ip)
|
||||
arp.protocol_address_size(sizeof(Ipv4_address));
|
||||
arp.opcode(Arp_packet::REQUEST);
|
||||
arp.src_mac(_router_mac);
|
||||
arp.src_ip(_router_ip());
|
||||
arp.src_ip(src_ip);
|
||||
arp.dst_mac(Mac_address(0xff));
|
||||
arp.dst_ip(ip);
|
||||
arp.dst_ip(dst_ip);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Interface::_handle_arp_reply(Ethernet_frame ð,
|
||||
size_t const eth_size,
|
||||
Arp_packet &arp)
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain)
|
||||
{
|
||||
try {
|
||||
/* check wether a matching ARP cache entry already exists */
|
||||
_domain.arp_cache().find_by_ip(arp.src_ip());
|
||||
if (_config().verbose()) {
|
||||
local_domain.arp_cache().find_by_ip(arp.src_ip());
|
||||
if (_config.verbose()) {
|
||||
log("ARP entry already exists"); }
|
||||
}
|
||||
catch (Arp_cache::No_match) {
|
||||
|
||||
/* by now, no matching ARP cache entry exists, so create one */
|
||||
Ipv4_address const ip = arp.src_ip();
|
||||
_domain.arp_cache().new_entry(ip, arp.src_mac());
|
||||
local_domain.arp_cache().new_entry(ip, arp.src_mac());
|
||||
|
||||
/* continue handling of packets that waited for the entry */
|
||||
for (Arp_waiter_list_element *waiter_le = _domain.foreign_arp_waiters().first();
|
||||
for (Arp_waiter_list_element *waiter_le = local_domain.foreign_arp_waiters().first();
|
||||
waiter_le; )
|
||||
{
|
||||
Arp_waiter &waiter = *waiter_le->object();
|
||||
@ -728,24 +762,19 @@ void Interface::_handle_arp_reply(Ethernet_frame ð,
|
||||
destroy(waiter.src()._alloc, &waiter);
|
||||
}
|
||||
}
|
||||
if (_ip_config().interface.prefix_matches(arp.dst_ip()) &&
|
||||
arp.dst_ip() != _router_ip())
|
||||
Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface;
|
||||
if (local_intf.prefix_matches(arp.dst_ip()) &&
|
||||
arp.dst_ip() != local_intf.address)
|
||||
{
|
||||
/*
|
||||
* Packet targets IP local to the domain's subnet and doesn't target
|
||||
* the router. Thus, forward it to all other interfaces of the domain.
|
||||
*/
|
||||
_domain_broadcast(eth, eth_size);
|
||||
_domain_broadcast(eth, eth_size, local_domain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ipv4_address const &Interface::_router_ip() const
|
||||
{
|
||||
return _ip_config().interface.address;
|
||||
}
|
||||
|
||||
|
||||
void Interface::_send_arp_reply(Ethernet_frame ð,
|
||||
size_t const eth_size,
|
||||
Arp_packet &arp)
|
||||
@ -767,9 +796,12 @@ void Interface::_send_arp_reply(Ethernet_frame ð,
|
||||
|
||||
void Interface::_handle_arp_request(Ethernet_frame ð,
|
||||
size_t const eth_size,
|
||||
Arp_packet &arp)
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain)
|
||||
{
|
||||
if (_ip_config().interface.prefix_matches(arp.dst_ip())) {
|
||||
Ipv4_config const &local_ip_cfg = local_domain.ip_config();
|
||||
Ipv4_address_prefix const &local_intf = local_ip_cfg.interface;
|
||||
if (local_intf.prefix_matches(arp.dst_ip())) {
|
||||
|
||||
/* ARP request for an IP local to the domain's subnet */
|
||||
if (arp.src_ip() == arp.dst_ip()) {
|
||||
@ -777,7 +809,7 @@ void Interface::_handle_arp_request(Ethernet_frame ð,
|
||||
/* gratuitous ARP requests are not really necessary */
|
||||
throw Drop_packet_inform("gratuitous ARP request");
|
||||
|
||||
} else if (arp.dst_ip() == _router_ip()) {
|
||||
} else if (arp.dst_ip() == local_intf.address) {
|
||||
|
||||
/* ARP request for the routers IP at this domain */
|
||||
_send_arp_reply(eth, eth_size, arp);
|
||||
@ -785,13 +817,13 @@ void Interface::_handle_arp_request(Ethernet_frame ð,
|
||||
} else {
|
||||
|
||||
/* forward request to all other interfaces of the domain */
|
||||
_domain_broadcast(eth, eth_size);
|
||||
_domain_broadcast(eth, eth_size, local_domain);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* ARP request for an IP foreign to the domain's subnet */
|
||||
if (_ip_config().gateway_valid) {
|
||||
if (local_ip_cfg.gateway_valid) {
|
||||
|
||||
/* leave request up to the gateway of the domain */
|
||||
throw Drop_packet_inform("leave ARP request up to gateway");
|
||||
@ -805,7 +837,9 @@ void Interface::_handle_arp_request(Ethernet_frame ð,
|
||||
}
|
||||
|
||||
|
||||
void Interface::_handle_arp(Ethernet_frame ð, size_t const eth_size)
|
||||
void Interface::_handle_arp(Ethernet_frame ð,
|
||||
size_t const eth_size,
|
||||
Domain &local_domain)
|
||||
{
|
||||
/* ignore ARP regarding protocols other than IPv4 via ethernet */
|
||||
Arp_packet &arp = *eth.data<Arp_packet>(eth_size - sizeof(Ethernet_frame));
|
||||
@ -813,8 +847,8 @@ void Interface::_handle_arp(Ethernet_frame ð, size_t const eth_size)
|
||||
error("ARP for unknown protocol"); }
|
||||
|
||||
switch (arp.opcode()) {
|
||||
case Arp_packet::REPLY: _handle_arp_reply(eth, eth_size, arp); break;
|
||||
case Arp_packet::REQUEST: _handle_arp_request(eth, eth_size, arp); break;
|
||||
case Arp_packet::REPLY: _handle_arp_reply(eth, eth_size, arp, local_domain); break;
|
||||
case Arp_packet::REQUEST: _handle_arp_request(eth, eth_size, arp, local_domain); break;
|
||||
default: error("unknown ARP operation"); }
|
||||
}
|
||||
|
||||
@ -849,18 +883,19 @@ void Interface::_ready_to_ack()
|
||||
}
|
||||
|
||||
|
||||
void Interface::_destroy_dhcp_allocation(Dhcp_allocation &allocation)
|
||||
void Interface::_destroy_dhcp_allocation(Dhcp_allocation &allocation,
|
||||
Domain &local_domain)
|
||||
{
|
||||
_domain.dhcp_server().free_ip(allocation.ip());
|
||||
local_domain.dhcp_server().free_ip(allocation.ip());
|
||||
destroy(_alloc, &allocation);
|
||||
}
|
||||
|
||||
|
||||
void Interface::_destroy_released_dhcp_allocations()
|
||||
void Interface::_destroy_released_dhcp_allocations(Domain &local_domain)
|
||||
{
|
||||
while (Dhcp_allocation *allocation = _released_dhcp_allocations.first()) {
|
||||
_released_dhcp_allocations.remove(allocation);
|
||||
_destroy_dhcp_allocation(*allocation);
|
||||
_destroy_dhcp_allocation(*allocation, local_domain);
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,64 +904,72 @@ void Interface::_handle_eth(void *const eth_base,
|
||||
size_t const eth_size,
|
||||
Packet_descriptor const &pkt)
|
||||
{
|
||||
_domain.raise_rx_bytes(eth_size);
|
||||
|
||||
/* do garbage collection over transport-layer links and DHCP allocations */
|
||||
_destroy_dissolved_links<Udp_link>(_dissolved_udp_links, _alloc);
|
||||
_destroy_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
|
||||
_destroy_released_dhcp_allocations();
|
||||
|
||||
/* inspect and handle ethernet frame */
|
||||
try {
|
||||
Ethernet_frame *const eth = reinterpret_cast<Ethernet_frame *>(eth_base);
|
||||
if (_domain.verbose_packets()) {
|
||||
log("[", _domain, "] rcv ", *eth); }
|
||||
Domain &local_domain = _domain_ptr.deref();
|
||||
try {
|
||||
local_domain.raise_rx_bytes(eth_size);
|
||||
|
||||
if (_domain.ip_config().valid) {
|
||||
/* do garbage collection over transport-layer links and DHCP allocations */
|
||||
_destroy_dissolved_links<Udp_link>(_dissolved_udp_links, _alloc);
|
||||
_destroy_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
|
||||
_destroy_released_dhcp_allocations(local_domain);
|
||||
|
||||
switch (eth->type()) {
|
||||
case Ethernet_frame::Type::ARP: _handle_arp(*eth, eth_size); break;
|
||||
case Ethernet_frame::Type::IPV4: _handle_ip(*eth, eth_size, pkt); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
/* inspect and handle ethernet frame */
|
||||
Ethernet_frame *const eth = reinterpret_cast<Ethernet_frame *>(eth_base);
|
||||
if (local_domain.verbose_packets()) {
|
||||
log("[", local_domain, "] rcv ", *eth); }
|
||||
|
||||
} else {
|
||||
if (local_domain.ip_config().valid) {
|
||||
|
||||
switch (eth->type()) {
|
||||
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(*eth, eth_size); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
switch (eth->type()) {
|
||||
case Ethernet_frame::Type::ARP: _handle_arp(*eth, eth_size, local_domain); break;
|
||||
case Ethernet_frame::Type::IPV4: _handle_ip(*eth, eth_size, pkt, local_domain); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
|
||||
} else {
|
||||
|
||||
switch (eth->type()) {
|
||||
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(*eth, eth_size); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
}
|
||||
}
|
||||
catch (Ethernet_frame::Bad_data_type) { warning("malformed Ethernet frame"); }
|
||||
catch (Ipv4_packet::Bad_data_type) { warning("malformed IPv4 packet" ); }
|
||||
catch (Udp_packet::Bad_data_type) { warning("malformed UDP packet" ); }
|
||||
|
||||
catch (Bad_network_protocol) {
|
||||
if (_config.verbose()) {
|
||||
log("unknown network layer protocol");
|
||||
}
|
||||
}
|
||||
catch (Drop_packet_inform exception) {
|
||||
if (_config.verbose()) {
|
||||
log("(", local_domain, ") Drop packet: ", exception.msg);
|
||||
}
|
||||
}
|
||||
catch (Drop_packet_warn exception) {
|
||||
warning("(", local_domain, ") Drop packet: ", exception.msg);
|
||||
}
|
||||
catch (Port_allocator_guard::Out_of_indices) {
|
||||
error("no available NAT ports"); }
|
||||
|
||||
catch (Domain::No_next_hop) {
|
||||
error("can not find next hop"); }
|
||||
|
||||
catch (Alloc_dhcp_msg_buffer_failed) {
|
||||
error("failed to allocate buffer for DHCP reply"); }
|
||||
|
||||
catch (Dhcp_msg_buffer_too_small) {
|
||||
error("DHCP reply buffer too small"); }
|
||||
|
||||
catch (Dhcp_server::Alloc_ip_failed) {
|
||||
error("failed to allocate IP for DHCP client"); }
|
||||
}
|
||||
catch (Pointer<Domain>::Invalid) {
|
||||
if (_config.verbose()) {
|
||||
log("(?) Drop packet: no domain");
|
||||
}
|
||||
}
|
||||
catch (Ethernet_frame::Bad_data_type) { warning("malformed Ethernet frame"); }
|
||||
catch (Ipv4_packet::Bad_data_type) { warning("malformed IPv4 packet" ); }
|
||||
catch (Udp_packet::Bad_data_type) { warning("malformed UDP packet" ); }
|
||||
|
||||
catch (Bad_network_protocol) {
|
||||
if (_config().verbose()) {
|
||||
log("unknown network layer protocol");
|
||||
}
|
||||
}
|
||||
catch (Drop_packet_inform exception) {
|
||||
if (_config().verbose()) {
|
||||
log("(", _domain, ") Drop packet: ", exception.msg);
|
||||
}
|
||||
}
|
||||
catch (Drop_packet_warn exception) {
|
||||
warning("(", _domain, ") Drop packet: ", exception.msg);
|
||||
}
|
||||
catch (Port_allocator_guard::Out_of_indices) {
|
||||
error("no available NAT ports"); }
|
||||
|
||||
catch (Domain::No_next_hop) {
|
||||
error("can not find next hop"); }
|
||||
|
||||
catch (Alloc_dhcp_msg_buffer_failed) {
|
||||
error("failed to allocate buffer for DHCP reply"); }
|
||||
|
||||
catch (Dhcp_msg_buffer_too_small) {
|
||||
error("DHCP reply buffer too small"); }
|
||||
|
||||
catch (Dhcp_server::Alloc_ip_failed) {
|
||||
error("failed to allocate IP for DHCP client"); }
|
||||
}
|
||||
|
||||
|
||||
@ -951,37 +994,39 @@ void Interface::_send_submit_pkt(Packet_descriptor &pkt,
|
||||
void * &pkt_base,
|
||||
size_t pkt_size)
|
||||
{
|
||||
Domain &local_domain = _domain_ptr.deref();
|
||||
_source().submit_packet(pkt);
|
||||
_domain.raise_tx_bytes(pkt_size);
|
||||
if (_domain.verbose_packets()) {
|
||||
log("[", _domain, "] snd ",
|
||||
local_domain.raise_tx_bytes(pkt_size);
|
||||
if (local_domain.verbose_packets()) {
|
||||
log("[", local_domain, "] snd ",
|
||||
*reinterpret_cast<Ethernet_frame *>(pkt_base));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Interface::Interface(Genode::Entrypoint &ep,
|
||||
Timer::Connection &timer,
|
||||
Mac_address const router_mac,
|
||||
Genode::Allocator &alloc,
|
||||
Mac_address const mac,
|
||||
Domain &domain)
|
||||
Interface::Interface(Genode::Entrypoint &ep,
|
||||
Timer::Connection &timer,
|
||||
Mac_address const router_mac,
|
||||
Genode::Allocator &alloc,
|
||||
Mac_address const mac,
|
||||
Configuration &config,
|
||||
Interface_policy const &policy)
|
||||
:
|
||||
_sink_ack(ep, *this, &Interface::_ack_avail),
|
||||
_sink_submit(ep, *this, &Interface::_ready_to_submit),
|
||||
_source_ack(ep, *this, &Interface::_ready_to_ack),
|
||||
_source_submit(ep, *this, &Interface::_packet_avail),
|
||||
_router_mac(router_mac), _mac(mac), _timer(timer), _alloc(alloc),
|
||||
_domain(domain)
|
||||
_router_mac(router_mac), _mac(mac), _config(config),
|
||||
_policy(policy), _timer(timer), _alloc(alloc)
|
||||
{
|
||||
_domain.manage_interface(*this);
|
||||
}
|
||||
|
||||
|
||||
void Interface::_init()
|
||||
{
|
||||
if (!_domain.ip_config().valid) {
|
||||
_dhcp_client.discover();
|
||||
/* try to find matching domain and attach interface to it */
|
||||
Domain_name const domain_name = _policy.determine_domain_name();
|
||||
try { attach_to_domain(config.domains().find_by_name(domain_name)); }
|
||||
catch (Domain_tree::No_match) {
|
||||
if (config.verbose()) {
|
||||
log("No matching domain");
|
||||
}
|
||||
_config.detached_interfaces().insert(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1006,28 +1051,31 @@ void Interface::cancel_arp_waiting(Arp_waiter &waiter)
|
||||
|
||||
Interface::~Interface()
|
||||
{
|
||||
_domain.dissolve_interface(*this);
|
||||
try {
|
||||
/* try to detach from domain */
|
||||
Domain &local_domain = _domain_ptr.deref();
|
||||
local_domain.detach_interface(*this);
|
||||
|
||||
/* destroy our own ARP waiters */
|
||||
while (_own_arp_waiters.first()) {
|
||||
cancel_arp_waiting(*_own_arp_waiters.first()->object());
|
||||
}
|
||||
/* destroy links */
|
||||
_destroy_links<Tcp_link>(_tcp_links, _dissolved_tcp_links, _alloc);
|
||||
_destroy_links<Udp_link>(_udp_links, _dissolved_udp_links, _alloc);
|
||||
/* destroy our own ARP waiters */
|
||||
while (_own_arp_waiters.first()) {
|
||||
cancel_arp_waiting(*_own_arp_waiters.first()->object());
|
||||
}
|
||||
/* destroy links */
|
||||
_destroy_links<Tcp_link>(_tcp_links, _dissolved_tcp_links, _alloc);
|
||||
_destroy_links<Udp_link>(_udp_links, _dissolved_udp_links, _alloc);
|
||||
|
||||
/* destroy DHCP allocations */
|
||||
_destroy_released_dhcp_allocations();
|
||||
while (Dhcp_allocation *allocation = _dhcp_allocations.first()) {
|
||||
_dhcp_allocations.remove(allocation);
|
||||
_destroy_dhcp_allocation(*allocation);
|
||||
/* destroy DHCP allocations */
|
||||
_destroy_released_dhcp_allocations(local_domain);
|
||||
while (Dhcp_allocation *allocation = _dhcp_allocations.first()) {
|
||||
_dhcp_allocations.remove(allocation);
|
||||
_destroy_dhcp_allocation(*allocation, local_domain);
|
||||
}
|
||||
/* dissolve ARP cache entries with the MAC address of this interface */
|
||||
local_domain.arp_cache().destroy_entries_with_mac(_mac);
|
||||
}
|
||||
catch (Pointer<Domain>::Invalid) {
|
||||
|
||||
/* if not attached to a domain the interface is in a global list */
|
||||
_config.detached_interfaces().remove(this);
|
||||
}
|
||||
/* dissolve ARP cache entries with the MAC address of this interface */
|
||||
_domain.arp_cache().destroy_entries_with_mac(_mac);
|
||||
}
|
||||
|
||||
|
||||
Configuration &Interface::_config() const { return _domain.config(); }
|
||||
|
||||
|
||||
Ipv4_config const &Interface::_ip_config() const { return _domain.ip_config(); }
|
||||
|
@ -31,11 +31,13 @@ namespace Net {
|
||||
using Packet_descriptor = ::Nic::Packet_descriptor;
|
||||
using Packet_stream_sink = ::Nic::Packet_stream_sink< ::Nic::Session::Policy>;
|
||||
using Packet_stream_source = ::Nic::Packet_stream_source< ::Nic::Session::Policy>;
|
||||
using Domain_name = Genode::String<160>;
|
||||
class Ipv4_config;
|
||||
class Forward_rule_tree;
|
||||
class Transport_rule_list;
|
||||
class Ethernet_frame;
|
||||
class Arp_packet;
|
||||
class Interface_policy;
|
||||
class Interface;
|
||||
class Dhcp_server;
|
||||
class Configuration;
|
||||
@ -43,6 +45,14 @@ namespace Net {
|
||||
}
|
||||
|
||||
|
||||
struct Net::Interface_policy
|
||||
{
|
||||
virtual Domain_name determine_domain_name() const = 0;
|
||||
|
||||
virtual ~Interface_policy() { }
|
||||
};
|
||||
|
||||
|
||||
class Net::Interface : private Genode::List<Interface>::Element
|
||||
{
|
||||
protected:
|
||||
@ -52,28 +62,28 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
|
||||
using Signal_handler = Genode::Signal_handler<Interface>;
|
||||
|
||||
Signal_handler _sink_ack;
|
||||
Signal_handler _sink_submit;
|
||||
Signal_handler _source_ack;
|
||||
Signal_handler _source_submit;
|
||||
Mac_address const _router_mac;
|
||||
Mac_address const _mac;
|
||||
|
||||
void _init();
|
||||
Signal_handler _sink_ack;
|
||||
Signal_handler _sink_submit;
|
||||
Signal_handler _source_ack;
|
||||
Signal_handler _source_submit;
|
||||
Mac_address const _router_mac;
|
||||
Mac_address const _mac;
|
||||
|
||||
private:
|
||||
|
||||
Timer::Connection &_timer;
|
||||
Genode::Allocator &_alloc;
|
||||
Domain &_domain;
|
||||
Arp_waiter_list _own_arp_waiters { };
|
||||
Link_list _tcp_links { };
|
||||
Link_list _udp_links { };
|
||||
Link_list _dissolved_tcp_links { };
|
||||
Link_list _dissolved_udp_links { };
|
||||
Dhcp_allocation_tree _dhcp_allocations { };
|
||||
Dhcp_allocation_list _released_dhcp_allocations { };
|
||||
Dhcp_client _dhcp_client { _alloc, _timer, *this };
|
||||
Configuration &_config;
|
||||
Interface_policy const &_policy;
|
||||
Timer::Connection &_timer;
|
||||
Genode::Allocator &_alloc;
|
||||
Pointer<Domain> _domain_ptr { };
|
||||
Arp_waiter_list _own_arp_waiters { };
|
||||
Link_list _tcp_links { };
|
||||
Link_list _udp_links { };
|
||||
Link_list _dissolved_tcp_links { };
|
||||
Link_list _dissolved_udp_links { };
|
||||
Dhcp_allocation_tree _dhcp_allocations { };
|
||||
Dhcp_allocation_list _released_dhcp_allocations { };
|
||||
Dhcp_client _dhcp_client { _alloc, _timer, *this };
|
||||
|
||||
void _new_link(L3_protocol const protocol,
|
||||
Link_side_id const &local_id,
|
||||
@ -81,35 +91,45 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
Domain &remote_domain,
|
||||
Link_side_id const &remote_id);
|
||||
|
||||
void _destroy_released_dhcp_allocations();
|
||||
void _destroy_released_dhcp_allocations(Domain &local_domain);
|
||||
|
||||
void _destroy_dhcp_allocation(Dhcp_allocation &allocation);
|
||||
void _destroy_dhcp_allocation(Dhcp_allocation &allocation,
|
||||
Domain &local_domain);
|
||||
|
||||
void _release_dhcp_allocation(Dhcp_allocation &allocation);
|
||||
void _release_dhcp_allocation(Dhcp_allocation &allocation,
|
||||
Domain &local_domain);
|
||||
|
||||
void _new_dhcp_allocation(Ethernet_frame ð,
|
||||
Dhcp_packet &dhcp,
|
||||
Dhcp_server &dhcp_srv);
|
||||
Dhcp_server &dhcp_srv,
|
||||
Domain &local_domain);
|
||||
|
||||
void _send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
Mac_address const &client_mac,
|
||||
Ipv4_address const &client_ip,
|
||||
Dhcp_packet::Message_type msg_type,
|
||||
Genode::uint32_t xid);
|
||||
Genode::uint32_t xid,
|
||||
Ipv4_address_prefix const &local_intf);
|
||||
|
||||
Forward_rule_tree &_forward_rules(L3_protocol const prot) const;
|
||||
Forward_rule_tree &_forward_rules(Domain &local_domain,
|
||||
L3_protocol const prot) const;
|
||||
|
||||
Transport_rule_list &_transport_rules(L3_protocol const prot) const;
|
||||
Transport_rule_list &_transport_rules(Domain &local_domain,
|
||||
L3_protocol const prot) const;
|
||||
|
||||
void _handle_arp(Ethernet_frame ð, Genode::size_t const eth_size);
|
||||
void _handle_arp(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_arp_reply(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
Arp_packet &arp);
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_arp_request(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
Arp_packet &arp);
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain);
|
||||
|
||||
void _send_arp_reply(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
@ -117,17 +137,18 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
|
||||
void _handle_dhcp_request(Ethernet_frame ð,
|
||||
Genode::size_t eth_size,
|
||||
Dhcp_packet &dhcp);
|
||||
Dhcp_packet &dhcp,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_ip(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
Packet_descriptor const &pkt);
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain);
|
||||
|
||||
void _adapt_eth(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
Ipv4_address const &ip,
|
||||
Ipv4_address const &dst_ip,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &domain);
|
||||
Domain &remote_domain);
|
||||
|
||||
void _nat_link_and_pass(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
@ -136,11 +157,15 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
void *const prot_base,
|
||||
Genode::size_t const prot_size,
|
||||
Link_side_id const &local_id,
|
||||
Domain &domain);
|
||||
Domain &local_domain,
|
||||
Domain &remote_domain);
|
||||
|
||||
void _broadcast_arp_request(Ipv4_address const &ip);
|
||||
void _broadcast_arp_request(Ipv4_address const &src_ip,
|
||||
Ipv4_address const &dst_ip);
|
||||
|
||||
void _domain_broadcast(Ethernet_frame ð, Genode::size_t eth_size);
|
||||
void _domain_broadcast(Ethernet_frame ð,
|
||||
Genode::size_t eth_size,
|
||||
Domain &local_domain);
|
||||
|
||||
void _pass_prot(Ethernet_frame ð,
|
||||
Genode::size_t const eth_size,
|
||||
@ -155,10 +180,6 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
|
||||
void _continue_handle_eth(Packet_descriptor const &pkt);
|
||||
|
||||
Configuration &_config() const;
|
||||
|
||||
Ipv4_config const &_ip_config() const;
|
||||
|
||||
Ipv4_address const &_router_ip() const;
|
||||
|
||||
void _handle_eth(void *const eth_base,
|
||||
@ -214,12 +235,13 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
Drop_packet_warn(ARGS... args) : msg({args...}) { }
|
||||
};
|
||||
|
||||
Interface(Genode::Entrypoint &ep,
|
||||
Timer::Connection &timer,
|
||||
Mac_address const router_mac,
|
||||
Genode::Allocator &alloc,
|
||||
Mac_address const mac,
|
||||
Domain &domain);
|
||||
Interface(Genode::Entrypoint &ep,
|
||||
Timer::Connection &timer,
|
||||
Mac_address const router_mac,
|
||||
Genode::Allocator &alloc,
|
||||
Mac_address const mac,
|
||||
Configuration &config,
|
||||
Interface_policy const &policy);
|
||||
|
||||
virtual ~Interface();
|
||||
|
||||
@ -249,12 +271,16 @@ class Net::Interface : private Genode::List<Interface>::Element
|
||||
|
||||
void cancel_arp_waiting(Arp_waiter &waiter);
|
||||
|
||||
void attach_to_domain(Domain &domain);
|
||||
|
||||
void detach_from_domain();
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Domain &domain() { return _domain; }
|
||||
Domain &domain() { return _domain_ptr.deref(); }
|
||||
Mac_address router_mac() const { return _router_mac; }
|
||||
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }
|
||||
};
|
||||
|
@ -31,11 +31,10 @@ Net::Uplink::Uplink(Env &env,
|
||||
Nic::Packet_allocator(&alloc),
|
||||
Nic::Connection(env, this, BUF_SIZE, BUF_SIZE),
|
||||
Net::Interface(env.ep(), timer, mac_address(), alloc, Mac_address(),
|
||||
config.domains().find_by_name(Cstring("uplink")))
|
||||
config, _intf_policy)
|
||||
{
|
||||
rx_channel()->sigh_ready_to_ack(_sink_ack);
|
||||
rx_channel()->sigh_packet_avail(_sink_submit);
|
||||
tx_channel()->sigh_ack_avail(_source_ack);
|
||||
tx_channel()->sigh_ready_to_submit(_source_submit);
|
||||
Interface::_init();
|
||||
}
|
||||
|
@ -22,9 +22,35 @@
|
||||
#include <interface.h>
|
||||
#include <ipv4_address_prefix.h>
|
||||
|
||||
namespace Net { class Uplink; }
|
||||
namespace Net {
|
||||
|
||||
class Net::Uplink : public Nic::Packet_allocator,
|
||||
using Domain_name = Genode::String<160>;
|
||||
class Uplink_base;
|
||||
class Uplink;
|
||||
}
|
||||
|
||||
|
||||
class Net::Uplink_base
|
||||
{
|
||||
protected:
|
||||
|
||||
struct Interface_policy : Net::Interface_policy
|
||||
{
|
||||
/***************************
|
||||
** Net::Interface_policy **
|
||||
***************************/
|
||||
|
||||
Domain_name determine_domain_name() const override { return Genode::Cstring("uplink"); };
|
||||
};
|
||||
|
||||
Interface_policy _intf_policy { };
|
||||
|
||||
virtual ~Uplink_base() { }
|
||||
};
|
||||
|
||||
|
||||
class Net::Uplink : public Uplink_base,
|
||||
public Nic::Packet_allocator,
|
||||
public Nic::Connection,
|
||||
public Interface
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user