475 lines
17 KiB
C++
475 lines
17 KiB
C++
/*
|
|
* \brief A net interface in form of a signal-driven NIC-packet handler
|
|
* \author Martin Stein
|
|
* \date 2016-08-24
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _INTERFACE_H_
|
|
#define _INTERFACE_H_
|
|
|
|
/* local includes */
|
|
#include <link.h>
|
|
#include <arp_waiter.h>
|
|
#include <l3_protocol.h>
|
|
#include <dhcp_client.h>
|
|
#include <dhcp_server.h>
|
|
#include <list.h>
|
|
#include <report.h>
|
|
|
|
/* Genode includes */
|
|
#include <nic_session/nic_session.h>
|
|
#include <net/dhcp.h>
|
|
#include <net/icmp.h>
|
|
|
|
namespace Genode { class Xml_generator; }
|
|
|
|
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;
|
|
using Interface_list = List<Interface>;
|
|
class Interface_link_stats;
|
|
class Interface_object_stats;
|
|
class Dhcp_server;
|
|
class Configuration;
|
|
class Domain;
|
|
}
|
|
|
|
|
|
struct Net::Interface_object_stats
|
|
{
|
|
Genode::size_t alive { 0 };
|
|
Genode::size_t destroyed { 0 };
|
|
|
|
void report(Genode::Xml_generator &xml);
|
|
|
|
~Interface_object_stats();
|
|
};
|
|
|
|
|
|
struct Net::Interface_link_stats
|
|
{
|
|
Genode::size_t refused_for_ram { 0 };
|
|
Genode::size_t refused_for_ports { 0 };
|
|
Genode::size_t opening { 0 };
|
|
Genode::size_t open { 0 };
|
|
Genode::size_t closing { 0 };
|
|
Genode::size_t closed { 0 };
|
|
Genode::size_t dissolved_timeout_opening { 0 };
|
|
Genode::size_t dissolved_timeout_open { 0 };
|
|
Genode::size_t dissolved_timeout_closing { 0 };
|
|
Genode::size_t dissolved_timeout_closed { 0 };
|
|
Genode::size_t dissolved_no_timeout { 0 };
|
|
Genode::size_t destroyed { 0 };
|
|
|
|
void report(Genode::Xml_generator &xml);
|
|
|
|
~Interface_link_stats();
|
|
};
|
|
|
|
|
|
struct Net::Interface_policy
|
|
{
|
|
virtual Domain_name determine_domain_name() const = 0;
|
|
|
|
virtual void handle_config(Configuration const &config) = 0;
|
|
|
|
virtual Genode::Session_label const &label() const = 0;
|
|
|
|
virtual void report(Genode::Xml_generator &) const { throw Report::Empty(); }
|
|
|
|
virtual ~Interface_policy() { }
|
|
};
|
|
|
|
|
|
class Net::Interface : private Interface_list::Element
|
|
{
|
|
friend class List<Interface>;
|
|
friend class Genode::List<Interface>;
|
|
|
|
private:
|
|
|
|
using Signal_handler = Genode::Signal_handler<Interface>;
|
|
using Signal_context_capability = Genode::Signal_context_capability;
|
|
|
|
enum { IPV4_TIME_TO_LIVE = 64 };
|
|
enum { MAX_FREE_OPS_PER_EMERGENCY = 1024 };
|
|
|
|
struct Dismiss_link : Genode::Exception { };
|
|
struct Dismiss_arp_waiter : Genode::Exception { };
|
|
|
|
struct Update_domain
|
|
{
|
|
Domain &old_domain;
|
|
Domain &new_domain;
|
|
|
|
Update_domain(Domain &old_domain,
|
|
Domain &new_domain)
|
|
:
|
|
old_domain(old_domain),
|
|
new_domain(new_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 { };
|
|
Genode::Constructible<Dhcp_client> _dhcp_client { };
|
|
Interface_list &_interfaces;
|
|
Genode::Constructible<Update_domain> _update_domain { };
|
|
Interface_link_stats _udp_stats { };
|
|
Interface_link_stats _tcp_stats { };
|
|
Interface_link_stats _icmp_stats { };
|
|
Interface_object_stats _arp_stats { };
|
|
Interface_object_stats _dhcp_stats { };
|
|
|
|
void _new_link(L3_protocol const protocol,
|
|
Link_side_id const &local_id,
|
|
Pointer<Port_allocator_guard> remote_port_alloc,
|
|
Domain &remote_domain,
|
|
Link_side_id const &remote_id);
|
|
|
|
void _destroy_released_dhcp_allocations(Domain &local_domain);
|
|
|
|
void _destroy_dhcp_allocation(Dhcp_allocation &allocation,
|
|
Domain &local_domain);
|
|
|
|
void _release_dhcp_allocation(Dhcp_allocation &allocation,
|
|
Domain &local_domain);
|
|
|
|
void _new_dhcp_allocation(Ethernet_frame ð,
|
|
Dhcp_packet &dhcp,
|
|
Dhcp_server &dhcp_srv,
|
|
Domain &local_domain);
|
|
|
|
void _send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
|
Mac_address const ð_dst,
|
|
Mac_address const &client_mac,
|
|
Ipv4_address const &client_ip,
|
|
Dhcp_packet::Message_type msg_type,
|
|
Genode::uint32_t xid,
|
|
Ipv4_address_prefix const &local_intf);
|
|
|
|
void _send_icmp_echo_reply(Ethernet_frame ð,
|
|
Ipv4_packet &ip,
|
|
Icmp_packet &icmp,
|
|
Genode::size_t icmp_sz,
|
|
Size_guard &size_guard);
|
|
|
|
Forward_rule_tree &_forward_rules(Domain &local_domain,
|
|
L3_protocol const prot) const;
|
|
|
|
Transport_rule_list &_transport_rules(Domain &local_domain,
|
|
L3_protocol const prot) const;
|
|
|
|
void _handle_arp(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Domain &local_domain);
|
|
|
|
void _handle_arp_reply(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Arp_packet &arp,
|
|
Domain &local_domain);
|
|
|
|
void _handle_arp_request(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Arp_packet &arp,
|
|
Domain &local_domain);
|
|
|
|
void _send_arp_reply(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Arp_packet &arp);
|
|
|
|
void _handle_dhcp_request(Ethernet_frame ð,
|
|
Dhcp_packet &dhcp,
|
|
Domain &local_domain);
|
|
|
|
void _handle_ip(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Packet_descriptor const &pkt,
|
|
Domain &local_domain);
|
|
|
|
void _handle_icmp_query(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Ipv4_packet &ip,
|
|
Packet_descriptor const &pkt,
|
|
L3_protocol prot,
|
|
void *prot_base,
|
|
Genode::size_t prot_size,
|
|
Domain &local_domain);
|
|
|
|
void _handle_icmp_error(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Ipv4_packet &ip,
|
|
Packet_descriptor const &pkt,
|
|
Domain &local_domain,
|
|
Icmp_packet &icmp,
|
|
Genode::size_t icmp_sz);
|
|
|
|
void _handle_icmp(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Ipv4_packet &ip,
|
|
Packet_descriptor const &pkt,
|
|
L3_protocol prot,
|
|
void *prot_base,
|
|
Genode::size_t prot_size,
|
|
Domain &local_domain,
|
|
Ipv4_address_prefix const &local_intf);
|
|
|
|
void _adapt_eth(Ethernet_frame ð,
|
|
Ipv4_address const &dst_ip,
|
|
Packet_descriptor const &pkt,
|
|
Domain &remote_domain);
|
|
|
|
void _nat_link_and_pass(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Ipv4_packet &ip,
|
|
L3_protocol const prot,
|
|
void *const prot_base,
|
|
Genode::size_t const prot_size,
|
|
Link_side_id const &local_id,
|
|
Domain &local_domain,
|
|
Domain &remote_domain);
|
|
|
|
void _broadcast_arp_request(Ipv4_address const &src_ip,
|
|
Ipv4_address const &dst_ip);
|
|
|
|
void _domain_broadcast(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Domain &local_domain);
|
|
|
|
void _pass_prot(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Ipv4_packet &ip,
|
|
L3_protocol const prot,
|
|
void *const prot_base,
|
|
Genode::size_t const prot_size);
|
|
|
|
void _pass_ip(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Ipv4_packet &ip);
|
|
|
|
void _handle_pkt();
|
|
|
|
void _continue_handle_eth(Domain const &domain,
|
|
Packet_descriptor const &pkt);
|
|
|
|
Ipv4_address const &_router_ip() const;
|
|
|
|
void _handle_eth(void *const eth_base,
|
|
Size_guard &size_guard,
|
|
Packet_descriptor const &pkt);
|
|
|
|
void _handle_eth(Ethernet_frame ð,
|
|
Size_guard &size_guard,
|
|
Packet_descriptor const &pkt,
|
|
Domain &local_domain);
|
|
|
|
void _ack_packet(Packet_descriptor const &pkt);
|
|
|
|
void _send_alloc_pkt(Genode::Packet_descriptor &pkt,
|
|
void * &pkt_base,
|
|
Genode::size_t pkt_size);
|
|
|
|
void _send_submit_pkt(Genode::Packet_descriptor &pkt,
|
|
void * &pkt_base,
|
|
Genode::size_t pkt_size);
|
|
|
|
void _update_dhcp_allocations(Domain &old_domain,
|
|
Domain &new_domain);
|
|
|
|
void _update_own_arp_waiters(Domain &domain);
|
|
|
|
void _update_udp_tcp_links(L3_protocol prot,
|
|
Domain &cln_dom);
|
|
|
|
void _update_icmp_links(Domain &cln_dom);
|
|
|
|
void _update_link_check_nat(Link &link,
|
|
Domain &new_srv_dom,
|
|
L3_protocol prot,
|
|
Domain &cln_dom);
|
|
|
|
void _dismiss_link_log(Link &link,
|
|
char const *reason);
|
|
|
|
void _destroy_link(Link &link);
|
|
|
|
void _update_domain_object(Domain &new_domain);
|
|
|
|
void _detach_from_domain_raw();
|
|
|
|
void _detach_from_domain();
|
|
|
|
void _attach_to_domain_raw(Domain &domain);
|
|
|
|
void _apply_foreign_arp();
|
|
|
|
void _failed_to_send_packet_link();
|
|
|
|
void _failed_to_send_packet_alloc();
|
|
|
|
void _send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf,
|
|
Ethernet_frame const &req_eth,
|
|
Ipv4_packet const &req_ip,
|
|
Icmp_packet::Code const code);
|
|
|
|
|
|
/***********************************
|
|
** Packet-stream signal handlers **
|
|
***********************************/
|
|
|
|
void _ready_to_submit();
|
|
void _ack_avail() { }
|
|
void _ready_to_ack();
|
|
void _packet_avail() { }
|
|
|
|
public:
|
|
|
|
struct Free_resources_and_retry_handle_eth : Genode::Exception { L3_protocol prot; Free_resources_and_retry_handle_eth(L3_protocol prot = (L3_protocol)0) : prot(prot) { } };
|
|
struct Bad_send_dhcp_args : Genode::Exception { };
|
|
struct Bad_transport_protocol : Genode::Exception { };
|
|
struct Bad_network_protocol : Genode::Exception { };
|
|
struct Packet_postponed : Genode::Exception { };
|
|
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
|
|
|
|
struct Drop_packet : Genode::Exception
|
|
{
|
|
char const *reason;
|
|
|
|
Drop_packet(char const *reason) : reason(reason) { }
|
|
};
|
|
|
|
Interface(Genode::Entrypoint &ep,
|
|
Timer::Connection &timer,
|
|
Mac_address const router_mac,
|
|
Genode::Allocator &alloc,
|
|
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();
|
|
|
|
void dhcp_allocation_expired(Dhcp_allocation &allocation);
|
|
|
|
template <typename FUNC>
|
|
void send(Genode::size_t pkt_size, FUNC && write_to_pkt)
|
|
{
|
|
if (!link_state()) {
|
|
_failed_to_send_packet_link();
|
|
return;
|
|
}
|
|
try {
|
|
Packet_descriptor pkt;
|
|
void *pkt_base;
|
|
|
|
_send_alloc_pkt(pkt, pkt_base, pkt_size);
|
|
Size_guard size_guard(pkt_size);
|
|
write_to_pkt(pkt_base, size_guard);
|
|
_send_submit_pkt(pkt, pkt_base, pkt_size);
|
|
}
|
|
catch (Packet_stream_source::Packet_alloc_failed) {
|
|
_failed_to_send_packet_alloc();
|
|
}
|
|
}
|
|
|
|
void send(Ethernet_frame ð,
|
|
Size_guard &size_guard);
|
|
|
|
Link_list &dissolved_links(L3_protocol const protocol);
|
|
|
|
Link_list &links(L3_protocol const protocol);
|
|
|
|
void cancel_arp_waiting(Arp_waiter &waiter);
|
|
|
|
void handle_config_1(Configuration &config);
|
|
|
|
void handle_config_2();
|
|
|
|
void handle_config_3();
|
|
|
|
void attach_to_domain();
|
|
|
|
void detach_from_ip_config();
|
|
|
|
void attach_to_ip_config(Domain &domain,
|
|
Ipv4_config const &ip_config);
|
|
|
|
void detach_from_remote_ip_config();
|
|
|
|
void attach_to_remote_ip_config();
|
|
|
|
void attach_to_domain_finish();
|
|
|
|
bool link_state() const;
|
|
|
|
void handle_link_state();
|
|
|
|
void report(Genode::Xml_generator &xml);
|
|
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Configuration const &config() const { return _config(); }
|
|
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; }
|
|
Interface_link_stats &udp_stats() { return _udp_stats; }
|
|
Interface_link_stats &tcp_stats() { return _tcp_stats; }
|
|
Interface_link_stats &icmp_stats() { return _icmp_stats; }
|
|
Interface_object_stats &arp_stats() { return _arp_stats; }
|
|
Interface_object_stats &dhcp_stats() { return _dhcp_stats; }
|
|
|
|
void session_link_state_sigh(Genode::Signal_context_capability sigh);
|
|
};
|
|
|
|
#endif /* _INTERFACE_H_ */
|