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

361 lines
10 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.
*/
#ifndef _COMPONENT_H_
#define _COMPONENT_H_
/* Genode includes */
#include <base/heap.h>
#include <root/component.h>
#include <nic/packet_allocator.h>
#include <nic_session/rpc_object.h>
/* local includes */
#include <mac_allocator.h>
#include <interface.h>
#include <reference.h>
#include <report.h>
namespace Genode { class Session_env; }
namespace Net {
class Communication_buffer;
class Session_component_base;
class Session_component;
class Root;
}
class Genode::Session_env : public Ram_allocator,
public Region_map
{
private:
Env &_env;
Net::Quota &_shared_quota;
Ram_quota_guard _ram_guard;
Cap_quota_guard _cap_guard;
template <typename FUNC>
void _consume(size_t own_ram,
size_t max_shared_ram,
size_t own_cap,
size_t max_shared_cap,
FUNC && functor)
{
size_t const max_ram_consumpt { own_ram + max_shared_ram };
size_t const max_cap_consumpt { own_cap + max_shared_cap };
size_t ram_consumpt { _env.pd().used_ram().value };
size_t cap_consumpt { _env.pd().used_caps().value };
{
Ram_quota_guard::Reservation ram_reserv { _ram_guard, Ram_quota { max_ram_consumpt } };
Cap_quota_guard::Reservation cap_reserv { _cap_guard, Cap_quota { max_cap_consumpt } };
functor();
ram_reserv.acknowledge();
cap_reserv.acknowledge();
}
ram_consumpt = _env.pd().used_ram().value - ram_consumpt;
cap_consumpt = _env.pd().used_caps().value - cap_consumpt;
if (ram_consumpt > max_ram_consumpt) {
error("Session_env: more RAM quota consumed than expected"); }
if (cap_consumpt > max_cap_consumpt) {
error("Session_env: more CAP quota consumed than expected"); }
if (ram_consumpt < own_ram) {
error("Session_env: less RAM quota consumed than expected"); }
if (cap_consumpt < own_cap) {
error("Session_env: less CAP quota consumed than expected"); }
_shared_quota.ram += ram_consumpt - own_ram;
_shared_quota.cap += cap_consumpt - own_cap;
_ram_guard.replenish( Ram_quota { max_shared_ram } );
_cap_guard.replenish( Cap_quota { max_shared_cap } );
}
template <typename FUNC>
void _replenish(size_t accounted_ram,
size_t accounted_cap,
FUNC && functor)
{
size_t ram_replenish { _env.pd().used_ram().value };
size_t cap_replenish { _env.pd().used_caps().value };
functor();
ram_replenish = ram_replenish - _env.pd().used_ram().value;
cap_replenish = cap_replenish - _env.pd().used_caps().value;
if (ram_replenish < accounted_ram) {
error("Session_env: less RAM quota replenished than expected"); }
if (cap_replenish < accounted_cap) {
error("Session_env: less CAP quota replenished than expected"); }
_shared_quota.ram -= ram_replenish - accounted_ram;
_shared_quota.cap -= cap_replenish - accounted_cap;
_ram_guard.replenish( Ram_quota { accounted_ram } );
_cap_guard.replenish( Cap_quota { accounted_cap } );
}
public:
Session_env(Env &env,
Net::Quota &shared_quota,
Ram_quota const &ram_quota,
Cap_quota const &cap_quota)
:
_env { env },
_shared_quota { shared_quota },
_ram_guard { ram_quota },
_cap_guard { cap_quota }
{ }
Entrypoint &ep() { return _env.ep(); }
/*******************
** Ram_allocator **
*******************/
Ram_dataspace_capability alloc(size_t size, Cache_attribute cached) override
{
enum { MAX_SHARED_CAP = 1 };
enum { MAX_SHARED_RAM = 4096 };
enum { DS_SIZE_GRANULARITY_LOG2 = 12 };
size_t const ds_size = align_addr(size, DS_SIZE_GRANULARITY_LOG2);
Ram_dataspace_capability ds;
_consume(ds_size, MAX_SHARED_RAM, 1, MAX_SHARED_CAP, [&] () {
ds = _env.pd().alloc(ds_size, cached);
});
return ds;
}
void free(Ram_dataspace_capability ds) override
{
_replenish(_env.pd().dataspace_size(ds), 1, [&] () {
_env.pd().free(ds);
});
}
size_t dataspace_size(Ram_dataspace_capability ds) const override { return _env.pd().dataspace_size(ds); }
/****************
** Region_map **
****************/
Local_addr attach(Dataspace_capability ds,
size_t size = 0,
off_t offset = 0,
bool use_local_addr = false,
Local_addr local_addr = (void *)0,
bool executable = false,
bool writeable = true) override
{
enum { MAX_SHARED_CAP = 2 };
enum { MAX_SHARED_RAM = 4 * 4096 };
void *ptr;
_consume(0, MAX_SHARED_RAM, 0, MAX_SHARED_CAP, [&] () {
ptr = _env.rm().attach(ds, size, offset, use_local_addr,
local_addr, executable, writeable);
});
return ptr;
};
void report(Genode::Xml_generator &xml) const
{
xml.node("ram-quota", [&] () {
xml.attribute("used", _ram_guard.used().value);
xml.attribute("limit", _ram_guard.limit().value);
xml.attribute("avail", _ram_guard.avail().value);
});
xml.node("cap-quota", [&] () {
xml.attribute("used", _cap_guard.used().value);
xml.attribute("limit", _cap_guard.limit().value);
xml.attribute("avail", _cap_guard.avail().value);
});
}
void detach(Local_addr local_addr) override
{
_replenish(0, 0, [&] () { _env.rm().detach(local_addr); });
}
void fault_handler(Signal_context_capability handler) override { _env.rm().fault_handler(handler); }
State state() override { return _env.rm().state(); }
Dataspace_capability dataspace() override { return _env.rm().dataspace(); }
/***************
** Accessors **
***************/
Ram_quota_guard const &ram_guard() const { return _ram_guard; };
Cap_quota_guard const &cap_guard() const { return _cap_guard; };
};
class Net::Communication_buffer
{
private:
Genode::Ram_allocator &_ram_alloc;
Genode::Ram_dataspace_capability _ram_ds;
public:
Communication_buffer(Genode::Ram_allocator &ram_alloc,
Genode::size_t const size);
~Communication_buffer() { _ram_alloc.free(_ram_ds); }
/***************
** Accessors **
***************/
Genode::Dataspace_capability ds() const { return _ram_ds; }
};
class Net::Session_component_base
{
protected:
Genode::Session_env &_session_env;
Genode::Heap _alloc;
Nic::Packet_allocator _packet_alloc;
Communication_buffer _tx_buf;
Communication_buffer _rx_buf;
public:
Session_component_base(Genode::Session_env &session_env,
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:
Genode::Session_label const _label;
Const_reference<Configuration> _config;
Genode::Session_env const &_session_env;
public:
Interface_policy(Genode::Session_label const &label,
Genode::Session_env const &session_env,
Configuration const &config);
/***************************
** Net::Interface_policy **
***************************/
Domain_name determine_domain_name() const override;
void handle_config(Configuration const &config) override { _config = config; }
Genode::Session_label const &label() const override { return _label; }
void report(Genode::Xml_generator &xml) const override { _session_env.report(xml); };
};
bool _link_state { true };
Interface_policy _interface_policy;
Interface _interface;
Genode::Ram_dataspace_capability const _ram_ds;
public:
Session_component(Genode::Session_env &session_env,
Genode::size_t const tx_buf_size,
Genode::size_t const rx_buf_size,
Timer::Connection &timer,
Mac_address const mac,
Mac_address const &router_mac,
Genode::Session_label const &label,
Interface_list &interfaces,
Configuration &config,
Genode::Ram_dataspace_capability const ram_ds);
/******************
** Nic::Session **
******************/
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); }
/***************
** Accessors **
***************/
Interface_policy const &interface_policy() const { return _interface_policy; }
Genode::Ram_dataspace_capability ram_ds() const { return _ram_ds; };
Genode::Session_env const &session_env() const { return _session_env; };
};
class Net::Root : public Genode::Root_component<Session_component>
{
private:
enum { MAC_ALLOC_BASE = 0x02 };
Genode::Env &_env;
Timer::Connection &_timer;
Mac_allocator _mac_alloc;
Mac_address const _router_mac;
Reference<Configuration> _config;
Quota &_shared_quota;
Interface_list &_interfaces;
void _invalid_downlink(char const *reason);
/********************
** Root_component **
********************/
Session_component *_create_session(char const *args) override;
void _destroy_session(Session_component *session) override;
public:
Root(Genode::Env &env,
Timer::Connection &timer,
Genode::Allocator &alloc,
Configuration &config,
Quota &shared_quota,
Interface_list &interfaces);
void handle_config(Configuration &config) { _config = Reference<Configuration>(config); }
};
#endif /* _COMPONENT_H_ */