nic_router: fix pure virtual call in ~Interface()

The interface destructor called pure virtual methods at least when
cancelling ARP- waiting states. The implementations were made by the
deriving classes Session_component respectively Uplink. This led to an
abort of the NIC router as the destruction of the derived class was
already done. A similar problem already occured in the past during the
construction of Interface and was back then solved by introducing a
separate init() method. This commit, however, solved the problem by
making Interface a member of the other classes. Therefore, the init()
method could be removed again. Furthermore, the interface polica could be
moved from Session_component_base to Session_component. The commit also
had to generalize the way the link state of an interface is determined.

Fixes #2856
This commit is contained in:
Martin Stein 2018-06-07 16:17:08 +02:00 committed by Christian Helmuth
parent fca3e59e26
commit 97ea513122
8 changed files with 156 additions and 171 deletions

View File

@ -42,28 +42,26 @@ 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)
size_t const rx_buf_size)
:
_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), _intf_policy(label, config)
_rx_buf(buf_ram, rx_buf_size)
{ }
/**********************************************
** Session_component_base::Interface_policy **
**********************************************/
/*****************************************
** Session_component::Interface_policy **
*****************************************/
Net::Session_component_base::
Net::Session_component::
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
Net::Session_component::Interface_policy::determine_domain_name() const
{
Domain_name domain_name;
try {
@ -94,28 +92,19 @@ Net::Session_component::Session_component(Allocator &alloc,
Interface_list &interfaces,
Configuration &config)
:
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, config, interfaces,
_intf_policy)
Session_component_base { alloc, amount, buf_ram, tx_buf_size,
rx_buf_size },
Session_rpc_object { region_map, _tx_buf, _rx_buf, &_range_alloc,
ep.rpc_ep() },
_interface_policy { label, config },
_interface { ep, timer, router_mac, _guarded_alloc, mac,
config, interfaces, *_tx.sink(), *_rx.source(),
_link_state, _interface_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);
}
bool Net::Session_component::_link_state()
{
try {
domain();
return true;
}
catch (Pointer<Domain>::Invalid) { }
return false;
_tx.sigh_ready_to_ack (_interface.sink_ack());
_tx.sigh_packet_avail (_interface.sink_submit());
_rx.sigh_ack_avail (_interface.source_ack());
_rx.sigh_ready_to_submit(_interface.source_submit());
}
@ -164,14 +153,11 @@ Session_component *Net::Root::_create_session(char const *args)
throw Insufficient_ram_quota();
}
Session_label const label(label_from_args(args));
Session_component &component = *new (md_alloc())
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, label,
_interfaces, _config());
component.init();
return &component;
}
catch (Mac_allocator::Alloc_failed) {
error("failed to allocate MAC address");

View File

@ -53,6 +53,26 @@ class Net::Session_component_base
{
protected:
Genode::Allocator_guard _guarded_alloc;
Nic::Packet_allocator _range_alloc;
Communication_buffer _tx_buf;
Communication_buffer _rx_buf;
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);
};
class Net::Session_component : private Session_component_base,
public ::Nic::Session_rpc_object
{
private:
struct Interface_policy : Net::Interface_policy
{
private:
@ -74,37 +94,9 @@ class Net::Session_component_base
void handle_config(Configuration const &config) override { _config = config; }
};
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,
Configuration const &config,
Genode::Session_label const &label);
};
class Net::Session_component : private Session_component_base,
public ::Nic::Session_rpc_object,
public Interface
{
private:
/********************
** Net::Interface **
********************/
Packet_stream_sink &_sink() override { return *_tx.sink(); }
Packet_stream_source &_source() override { return *_rx.source(); }
bool _link_state() override;
bool _link_state { true };
Interface_policy _interface_policy;
Interface _interface;
public:
@ -127,9 +119,10 @@ class Net::Session_component : private Session_component_base,
** Nic::Session **
******************/
Mac_address mac_address() override { return _mac; }
bool link_state() override { return _link_state(); }
void link_state_sigh(Genode::Signal_context_capability sigh) override { Interface::link_state_sigh(sigh); }
Mac_address mac_address() override { return _interface.mac(); }
bool link_state() override { return _interface.link_state(); }
void link_state_sigh(Genode::Signal_context_capability sigh) override {
_interface.session_link_state_sigh(sigh); }
};

View File

@ -236,7 +236,7 @@ Interface::_transport_rules(Domain &local_domain, L3_protocol const prot) const
void Interface::_attach_to_domain_raw(Domain &domain)
{
_domain = domain;
Signal_transmitter(_link_state_sigh).submit();
Signal_transmitter(_session_link_state_sigh).submit();
_interfaces.remove(this);
domain.attach_interface(*this);
}
@ -248,7 +248,7 @@ void Interface::_detach_from_domain_raw()
domain.detach_interface(*this);
_interfaces.insert(this);
_domain = Pointer<Domain>();
Signal_transmitter(_link_state_sigh).submit();
Signal_transmitter(_session_link_state_sigh).submit();
}
@ -283,9 +283,9 @@ void Interface::attach_to_ip_config(Domain &domain,
}
void Interface::link_state_sigh(Signal_context_capability sigh)
void Interface::session_link_state_sigh(Signal_context_capability sigh)
{
_link_state_sigh = sigh;
_session_link_state_sigh = sigh;
}
@ -315,14 +315,14 @@ void Interface::detach_from_ip_config()
void Interface::detach_from_remote_ip_config()
{
/* only the DNS server address of the local DHCP server can be remote */
Signal_transmitter(_link_state_sigh).submit();
Signal_transmitter(_session_link_state_sigh).submit();
}
void Interface::attach_to_remote_ip_config()
{
/* only the DNS server address of the local DHCP server can be remote */
Signal_transmitter(_link_state_sigh).submit();
Signal_transmitter(_session_link_state_sigh).submit();
}
@ -725,6 +725,12 @@ void Interface::_send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf
}
bool Interface::link_state() const
{
return _domain.valid() && _session_link_state;
}
void Interface::_handle_icmp_query(Ethernet_frame &eth,
Size_guard &size_guard,
Ipv4_packet &ip,
@ -1168,10 +1174,10 @@ void Interface::_handle_arp(Ethernet_frame &eth,
void Interface::_ready_to_submit()
{
while (_sink().packet_avail()) {
Packet_descriptor const pkt = _sink().get_packet();
while (_sink.packet_avail()) {
Packet_descriptor const pkt = _sink.get_packet();
Size_guard size_guard(pkt.size());
try { _handle_eth(_sink().packet_content(pkt), size_guard, pkt); }
try { _handle_eth(_sink.packet_content(pkt), size_guard, pkt); }
catch (Packet_postponed) { continue; }
_ack_packet(pkt);
}
@ -1181,7 +1187,7 @@ void Interface::_ready_to_submit()
void Interface::_continue_handle_eth(Packet_descriptor const &pkt)
{
Size_guard size_guard(pkt.size());
try { _handle_eth(_sink().packet_content(pkt), size_guard, pkt); }
try { _handle_eth(_sink.packet_content(pkt), size_guard, pkt); }
catch (Packet_postponed) { error("failed twice to handle packet"); }
_ack_packet(pkt);
}
@ -1189,8 +1195,8 @@ void Interface::_continue_handle_eth(Packet_descriptor const &pkt)
void Interface::_ready_to_ack()
{
while (_source().ack_avail()) {
_source().release_packet(_source().get_acked_packet()); }
while (_source.ack_avail()) {
_source.release_packet(_source.get_acked_packet()); }
}
@ -1293,8 +1299,8 @@ void Interface::_send_alloc_pkt(Packet_descriptor &pkt,
void * &pkt_base,
size_t pkt_size)
{
pkt = _source().alloc_packet(pkt_size);
pkt_base = _source().packet_content(pkt);
pkt = _source.alloc_packet(pkt_size);
pkt_base = _source.packet_content(pkt);
}
@ -1312,7 +1318,7 @@ void Interface::_send_submit_pkt(Packet_descriptor &pkt,
}
catch (Size_guard::Exceeded) { log("[", local_domain, "] snd ?"); }
}
_source().submit_packet(pkt);
_source.submit_packet(pkt);
}
@ -1323,22 +1329,27 @@ Interface::Interface(Genode::Entrypoint &ep,
Mac_address const mac,
Configuration &config,
Interface_list &interfaces,
Packet_stream_sink &sink,
Packet_stream_source &source,
bool &session_link_state,
Interface_policy &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), _config(config),
_policy(policy), _timer(timer), _alloc(alloc),
_interfaces(interfaces)
_sink { sink },
_source { source },
_session_link_state { session_link_state },
_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 },
_config { config },
_policy { policy },
_timer { timer },
_alloc { alloc },
_interfaces { interfaces }
{
_interfaces.insert(this);
}
void Interface::init()
{
try { _attach_to_domain(_policy.determine_domain_name()); }
catch (Domain_tree::No_match) { }
}
@ -1650,11 +1661,11 @@ void Interface::handle_config_3()
void Interface::_ack_packet(Packet_descriptor const &pkt)
{
if (!_sink().ready_to_ack()) {
if (!_sink.ready_to_ack()) {
error("ack state FULL");
return;
}
_sink().acknowledge_packet(pkt);
_sink.acknowledge_packet(pkt);
}

View File

@ -62,19 +62,11 @@ class Net::Interface : private Interface_list::Element
friend class List<Interface>;
friend class Genode::List<Interface>;
protected:
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;
private:
using Signal_handler = Genode::Signal_handler<Interface>;
using Signal_context_capability = Genode::Signal_context_capability;
enum { IPV4_TIME_TO_LIVE = 64 };
struct Dismiss_link : Genode::Exception { };
@ -86,24 +78,33 @@ class Net::Interface : private Interface_list::Element
Domain &new_domain;
};
Reference<Configuration> _config;
Interface_policy &_policy;
Timer::Connection &_timer;
Genode::Allocator &_alloc;
Pointer<Domain> _domain { };
Arp_waiter_list _own_arp_waiters { };
Link_list _tcp_links { };
Link_list _udp_links { };
Link_list _icmp_links { };
Link_list _dissolved_tcp_links { };
Link_list _dissolved_udp_links { };
Link_list _dissolved_icmp_links { };
Dhcp_allocation_tree _dhcp_allocations { };
Dhcp_allocation_list _released_dhcp_allocations { };
Dhcp_client _dhcp_client { _alloc, _timer, *this };
Interface_list &_interfaces;
Genode::Signal_context_capability _link_state_sigh { };
Pointer<Update_domain> _update_domain { };
Packet_stream_sink &_sink;
Packet_stream_source &_source;
bool &_session_link_state;
Signal_context_capability _session_link_state_sigh { };
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;
Reference<Configuration> _config;
Interface_policy &_policy;
Timer::Connection &_timer;
Genode::Allocator &_alloc;
Pointer<Domain> _domain { };
Arp_waiter_list _own_arp_waiters { };
Link_list _tcp_links { };
Link_list _udp_links { };
Link_list _icmp_links { };
Link_list _dissolved_tcp_links { };
Link_list _dissolved_udp_links { };
Link_list _dissolved_icmp_links { };
Dhcp_allocation_tree _dhcp_allocations { };
Dhcp_allocation_list _released_dhcp_allocations { };
Dhcp_client _dhcp_client { _alloc, _timer, *this };
Interface_list &_interfaces;
Pointer<Update_domain> _update_domain { };
void _new_link(L3_protocol const protocol,
Link_side_id const &local_id,
@ -281,16 +282,6 @@ class Net::Interface : private Interface_list::Element
Ipv4_packet const &req_ip,
Icmp_packet::Code const code);
/*******************
** Pure virtuals **
*******************/
virtual Packet_stream_sink &_sink() = 0;
virtual Packet_stream_source &_source() = 0;
virtual bool _link_state() = 0;
/***********************************
** Packet-stream signal handlers **
@ -332,6 +323,9 @@ class Net::Interface : private Interface_list::Element
Mac_address const mac,
Configuration &config,
Interface_list &interfaces,
Packet_stream_sink &sink,
Packet_stream_source &source,
bool &session_link_state,
Interface_policy &policy);
virtual ~Interface();
@ -341,7 +335,7 @@ class Net::Interface : private Interface_list::Element
template <typename FUNC>
void send(Genode::size_t pkt_size, FUNC && write_to_pkt)
{
if (!_link_state()) {
if (!link_state()) {
_failed_to_send_packet_link();
return;
}
@ -383,20 +377,25 @@ class Net::Interface : private Interface_list::Element
void attach_to_remote_ip_config();
void link_state_sigh(Genode::Signal_context_capability sigh);
void init();
void attach_to_domain_finish();
bool link_state() const;
/***************
** Accessors **
***************/
Domain &domain() { return _domain(); }
Mac_address router_mac() const { return _router_mac; }
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }
Domain &domain() { return _domain(); }
Mac_address const &router_mac() const { return _router_mac; }
Mac_address const &mac() const { return _mac; }
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }
Signal_handler &sink_ack() { return _sink_ack; }
Signal_handler &sink_submit() { return _sink_submit; }
Signal_handler &source_ack() { return _source_ack; }
Signal_handler &source_submit() { return _source_submit; }
void session_link_state_sigh(Genode::Signal_context_capability sigh);
};
#endif /* _INTERFACE_H_ */

View File

@ -103,7 +103,6 @@ void Net::Main::_init_uplink(Configuration &config,
Uplink &uplink = *new (_heap) Uplink(_env, _timer, _heap, _interfaces,
config, label);
_uplink = Pointer<Uplink>(uplink);
uplink.init();
}

View File

@ -46,6 +46,8 @@ class Net::Pointer
return *_obj;
}
bool valid() const { return _obj != nullptr; }
};

View File

@ -30,25 +30,29 @@ Net::Uplink::Uplink(Env &env,
Configuration &config,
Session_label const &label)
:
Nic::Packet_allocator(&alloc),
Nic::Connection(env, this, BUF_SIZE, BUF_SIZE, label.string()),
Net::Interface(env.ep(), timer, mac_address(), alloc, Mac_address(),
config, interfaces, _intf_policy),
_label(label),
_link_state_handler(env.ep(), *this, &Uplink::_handle_link_state)
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 },
_interface { env.ep(), timer, mac_address(), alloc,
Mac_address(), config, interfaces, *rx(), *tx(),
_link_state, _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);
/* install packet stream signal handlers */
rx_channel()->sigh_ready_to_ack (_interface.sink_ack());
rx_channel()->sigh_packet_avail (_interface.sink_submit());
tx_channel()->sigh_ack_avail (_interface.source_ack());
tx_channel()->sigh_ready_to_submit(_interface.source_submit());
/* initialize link state handling */
Nic::Connection::link_state_sigh(_link_state_handler);
_link_state_ = link_state();
_link_state = link_state();
}
void Net::Uplink::_handle_link_state()
{
_link_state_ = link_state();
try { domain().discard_ip_config(); }
_link_state = link_state();
try { _interface.domain().discard_ip_config(); }
catch (Domain::Ip_config_static) { }
}

View File

@ -52,8 +52,7 @@ class Net::Uplink_base
class Net::Uplink : public Uplink_base,
public Nic::Packet_allocator,
public Nic::Connection,
public Interface
public Nic::Connection
{
private:
@ -63,22 +62,14 @@ class Net::Uplink : public Uplink_base,
};
Genode::Session_label const &_label;
bool _link_state_ { false };
bool _link_state { false };
Genode::Signal_handler<Uplink> _link_state_handler;
Net::Interface _interface;
Ipv4_address_prefix _read_interface();
void _handle_link_state();
/********************
** Net::Interface **
********************/
Packet_stream_sink &_sink() override { return *rx(); }
Packet_stream_source &_source() override { return *tx(); }
bool _link_state() override { return _link_state_; }
public:
Uplink(Genode::Env &env,
@ -93,7 +84,7 @@ class Net::Uplink : public Uplink_base,
** Accessors **
***************/
Mac_address const &router_mac() const { return _router_mac; }
Mac_address const &router_mac() const { return _interface.router_mac(); }
Genode::Session_label const &label() const { return _label; }
};