genode/repos/os/src/server/nic_router/component.cc

266 lines
8.6 KiB
C++

/*
* \brief Downlink interface in form of a NIC session component
* \author Martin Stein
* \date 2016-08-23
*/
/*
* 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.
*/
/* Genode includes */
#include <os/session_policy.h>
/* local includes */
#include <component.h>
#include <configuration.h>
using namespace Net;
using namespace Genode;
/**************************
** Communication_buffer **
**************************/
Communication_buffer::Communication_buffer(Ram_allocator &ram_alloc,
size_t const size)
:
_ram_alloc { ram_alloc },
_ram_ds { ram_alloc.alloc(size) }
{ }
/****************************
** Session_component_base **
****************************/
Session_component_base::
Session_component_base(Session_env &session_env,
size_t const tx_buf_size,
size_t const rx_buf_size)
:
_session_env { session_env },
_alloc { _session_env, _session_env },
_packet_alloc { &_alloc },
_tx_buf { _session_env, tx_buf_size },
_rx_buf { _session_env, rx_buf_size }
{ }
/*****************************************
** Session_component::Interface_policy **
*****************************************/
Net::Session_component::
Interface_policy::Interface_policy(Genode::Session_label const &label,
Session_env const &session_env,
Configuration const &config)
:
_label { label },
_config { config },
_session_env { session_env }
{ }
Domain_name
Net::Session_component::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 policy for downlink label \"", _label, "\""); }
}
catch (Xml_node::Nonexistent_attribute) {
if (_config().verbose()) {
log("[?] no domain attribute in policy for downlink label \"",
_label, "\"");
}
}
return domain_name;
}
/***********************
** Session_component **
***********************/
Net::Session_component::Session_component(Session_env &session_env,
size_t const tx_buf_size,
size_t const rx_buf_size,
Timer::Connection &timer,
Mac_address const mac,
Mac_address const &router_mac,
Session_label const &label,
Interface_list &interfaces,
Configuration &config,
Ram_dataspace_capability const ram_ds)
:
Session_component_base { session_env, tx_buf_size,rx_buf_size },
Session_rpc_object { _session_env, _tx_buf.ds(), _rx_buf.ds(),
&_packet_alloc, _session_env.ep().rpc_ep() },
_interface_policy { label, _session_env, config },
_interface { _session_env.ep(), timer, router_mac, _alloc,
mac, config, interfaces, *_tx.sink(),
*_rx.source(), _link_state, _interface_policy },
_ram_ds { ram_ds }
{
_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());
_rx.sigh_ready_to_submit(_interface.source_submit());
}
/**********
** Root **
**********/
Net::Root::Root(Env &env,
Timer::Connection &timer,
Allocator &alloc,
Configuration &config,
Quota &shared_quota,
Interface_list &interfaces)
:
Root_component<Session_component> { &env.ep().rpc_ep(), &alloc },
_env { env },
_timer { timer },
_mac_alloc { MAC_ALLOC_BASE },
_router_mac { _mac_alloc.alloc() },
_config { config },
_shared_quota { shared_quota },
_interfaces { interfaces }
{ }
Session_component *Net::Root::_create_session(char const *args)
{
try {
/* create session environment temporarily on the stack */
Session_env session_env_stack { _env, _shared_quota,
Ram_quota { Arg_string::find_arg(args, "ram_quota").ulong_value(0) },
Cap_quota { Arg_string::find_arg(args, "cap_quota").ulong_value(0) } };
/* alloc/attach RAM block and move session env to base of the block */
Ram_dataspace_capability ram_ds {
session_env_stack.alloc(sizeof(Session_env) +
sizeof(Session_component), CACHED) };
try {
void * const ram_ptr { session_env_stack.attach(ram_ds) };
Session_env &session_env {
*construct_at<Session_env>(ram_ptr, session_env_stack) };
/* create new session object behind session env in the RAM block */
try {
Session_label const label { label_from_args(args) };
Mac_address const mac { _mac_alloc.alloc() };
try {
Session_component *x = construct_at<Session_component>(
(void*)((addr_t)ram_ptr + sizeof(Session_env)),
session_env,
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0),
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0),
_timer, mac, _router_mac, label, _interfaces,
_config(), ram_ds);
return x;
}
catch (Out_of_ram) {
_mac_alloc.free(mac);
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session RAM quota");
throw Insufficient_ram_quota();
}
catch (Out_of_caps) {
_mac_alloc.free(mac);
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session CAP quota");
throw Insufficient_cap_quota();
}
}
catch (Mac_allocator::Alloc_failed) {
Session_env session_env_stack { session_env };
session_env_stack.detach(ram_ptr);
session_env_stack.free(ram_ds);
_invalid_downlink("failed to allocate MAC address");
throw Service_denied();
}
}
catch (Region_map::Invalid_dataspace) {
session_env_stack.free(ram_ds);
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Region_map::Region_conflict) {
session_env_stack.free(ram_ds);
_invalid_downlink("Failed to attach RAM");
throw Service_denied();
}
catch (Out_of_ram) {
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session RAM quota");
throw Insufficient_ram_quota();
}
catch (Out_of_caps) {
session_env_stack.free(ram_ds);
_invalid_downlink("NIC session CAP quota");
throw Insufficient_cap_quota();
}
}
catch (Out_of_ram) {
_invalid_downlink("NIC session RAM quota");
throw Insufficient_ram_quota();
}
catch (Out_of_caps) {
_invalid_downlink("NIC session CAP quota");
throw Insufficient_cap_quota();
}
}
void Net::Root::_destroy_session(Session_component *session)
{
Mac_address const mac = session->mac_address();
/* read out initial dataspace and session env and destruct session */
Ram_dataspace_capability ram_ds { session->ram_ds() };
Session_env const &session_env { session->session_env() };
Session_label const session_label { session->interface_policy().label() };
session->~Session_component();
/* copy session env to stack and detach/free all session data */
Session_env session_env_stack { session_env };
session_env_stack.detach(session);
session_env_stack.detach(&session_env);
session_env_stack.free(ram_ds);
_mac_alloc.free(mac);
/* check for leaked quota */
if (session_env_stack.ram_guard().used().value) {
error("NIC session component \"", session_label, "\" leaks RAM quota of ",
session_env_stack.ram_guard().used().value, " byte(s)"); };
if (session_env_stack.cap_guard().used().value) {
error("NIC session component \"", session_label, "\" leaks CAP quota of ",
session_env_stack.cap_guard().used().value, " cap(s)"); };
}
void Net::Root::_invalid_downlink(char const *reason)
{
if (_config().verbose()) {
log("[?] invalid downlink (", reason, ")"); }
}