Add nic_bus service

This commit is contained in:
Ehmry - 2019-04-14 18:56:47 +02:00
parent 201e9e97fa
commit d23bd2c562
6 changed files with 400 additions and 0 deletions

View File

@ -0,0 +1,4 @@
The nic_bus server switches packets between sessions using Ethernet headers.
Sessions may only send and receive packets with MAC addresses assigned by
the bus. For this reason it does not support attachment to ethernet hubs or
switches and is therefore not intended for use with harware interfaces.

View File

@ -0,0 +1,16 @@
TARGET_NAME = nic_bus
include_rules
PKGS = genode-os genode-prg
: foreach *.cc |> ^ CC %o^ \
$(CC) -std=gnu++11 `pkg-config --cflags $(PKGS)` -c %f -o %o |> %B.o {objs}
: {objs} |> ^o LD %o^ \
$(LD) `pkg-config --libs $(PKGS)` %f -o %o |> %d {binary}
: {binary} |> !collect_bin |>
: |> !bin |>
PKG_DEPENDS += _/src/$(TARGET_NAME)
: runtime |> !collect_pkg_runtime |>

113
src/server/nic_bus/bus.h Normal file
View File

@ -0,0 +1,113 @@
/*
* \brief Nic session bus
* \author Emery Hemingway
* \date 2019-04-14
*/
/*
* Copyright (C) 2019 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 _NETWORK_STATE_H_
#define _NETWORK_STATE_H_
/* Genode includes */
#include <net/ethernet.h>
#include <base/session_label.h>
#include <util/xml_node.h>
namespace Nic_bus {
using namespace Net;
using namespace Genode;
struct Bus;
class Session_component;
Mac_address mac_address(Session_component &session);
}
struct Nic_bus::Bus
{
/* static array of sessions on the bus */
enum { BUS_SIZE = 0xffU };
Session_component *_sessions[BUS_SIZE] { nullptr };
static uint8_t _index(Mac_address const &mac) { return mac.addr[1]; };
Bus() { }
void remove(Mac_address const mac) {
_sessions[_index(mac)] = nullptr; }
Mac_address insert(Session_label const &label,
Session_component &session)
{
/**
* Derive a MAC address using the FNV-1a algorithm.
*/
enum {
FNV_32_PRIME = 16777619U,
FNV_32_OFFSET = 2166136261U,
};
uint32_t hash = FNV_32_OFFSET;
char const *p = label.string();
while (*p) {
hash ^= *p++;
hash *= FNV_32_PRIME;
}
for (;;) {
/* add the terminating zero */
hash *= FNV_32_PRIME;
uint8_t index = hash >> 24;
if (_sessions[index] != nullptr)
continue;
/* hash until a free slot is found */
_sessions[index] = &session;
Mac_address mac;
mac.addr[0] = 0x02;
mac.addr[1] = index;
mac.addr[2] = hash >> 24;
mac.addr[3] = hash >> 16;
mac.addr[4] = hash >> 8;
mac.addr[5] = hash;
return mac;
}
}
template<typename PROC>
void apply(Mac_address mac, PROC proc)
{
uint8_t const index = _index(mac);
Session_component *session = _sessions[index];
if (session != nullptr) {
if (mac_address(*session) == mac) {
proc(*session);
}
}
}
template<typename PROC>
void apply_all(PROC proc)
{
for (auto i = 0U; i < BUS_SIZE; ++i) {
Session_component *session = _sessions[i];
if (session != nullptr) {
proc(*session);
}
}
}
};
#endif

View File

@ -0,0 +1,93 @@
/*
* \brief Nic bus service
* \author Emery Hemingway
* \date 2019-04-10
*/
/*
* Copyright (C) 2019 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.
*/
/* local includes */
#include "session_component.h"
/* Genode */
#include <root/component.h>
#include <base/attached_rom_dataspace.h>
#include <os/session_policy.h>
#include <base/component.h>
namespace Nic_bus {
using namespace Net;
using namespace Genode;
class Root;
struct Main;
/* used by the bus */
Mac_address mac_address(Session_component &session) {
return session.mac_address(); }
}
class Nic_bus::Root : public Genode::Root_component<Nic_bus::Session_component>
{
private:
Genode::Env &_env;
Attached_rom_dataspace _config_rom { _env, "config" };
Bus _bus { };
protected:
Session_component *_create_session(const char *args) override
{
using namespace Genode;
_config_rom.update();
Session_label label { label_from_args(args) };
Session_policy policy { label, _config_rom.xml() };
return new (md_alloc())
Session_component(_env.ep(), _env.ram(), _env.rm(),
ram_quota_from_args(args),
cap_quota_from_args(args),
Tx_size{Arg_string::find_arg(args, "tx_buf_size").ulong_value(0)},
Rx_size{Arg_string::find_arg(args, "rx_buf_size").ulong_value(0)},
_bus,
label);
}
public:
Root(Genode::Env &env,
Genode::Allocator &md_alloc)
:
Genode::Root_component<Nic_bus::Session_component>(
env.ep(), md_alloc),
_env(env)
{ }
};
struct Nic_bus::Main
{
Sliced_heap _sliced_heap;
Nic_bus::Root _root;
Main(Genode::Env &env)
:
_sliced_heap(env.ram(), env.rm()),
_root(env, _sliced_heap)
{
env.parent().announce(env.ep().manage(_root));
}
};
void Component::construct(Genode::Env &env) { static Nic_bus::Main inst(env); }

View File

@ -0,0 +1,5 @@
<runtime ram="4M" caps="96" binary="nic_bus">
<provides> <nic/> </provides>
<content> <rom label="nic_bus"/> </content>
<config> <default-policy/></config>
</runtime>

View File

@ -0,0 +1,169 @@
/*
* \brief Nic bus session component
* \author Emery Hemingway
* \date 2019-04-14
*/
/*
* Copyright (C) 2019 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 _SESSION_COMPONENT_H_
#define _SESSION_COMPONENT_H_
/* local includes */
#include "bus.h"
/* Genode includes */
#include <net/ethernet.h>
#include <net/size_guard.h>
#include <nic/component.h>
#include <base/heap.h>
#include <base/session_label.h>
namespace Nic_bus {
using namespace Net;
struct Tx_size { Genode::size_t value; };
struct Rx_size { Genode::size_t value; };
class Session_resources;
class Session_component;
}
/**
* Base class to manage session quotas and allocations
*/
class Nic_bus::Session_resources
{
protected:
Genode::Ram_quota_guard _ram_guard;
Genode::Cap_quota_guard _cap_guard;
Genode::Constrained_ram_allocator _ram_alloc;
Genode::Attached_ram_dataspace _tx_ds, _rx_ds;
Genode::Heap _alloc;
Nic::Packet_allocator _rx_pkt_alloc { &_alloc };
Session_resources(Genode::Ram_allocator &ram,
Genode::Region_map &region_map,
Genode::Ram_quota ram_quota,
Genode::Cap_quota cap_quota,
Tx_size tx_size,
Rx_size rx_size)
:
_ram_guard(ram_quota), _cap_guard(cap_quota),
_ram_alloc(ram, _ram_guard, _cap_guard),
_tx_ds(_ram_alloc, region_map, tx_size.value),
_rx_ds(_ram_alloc, region_map, rx_size.value),
_alloc(_ram_alloc, region_map)
{ }
};
class Nic_bus::Session_component : private Session_resources,
public Nic::Session_rpc_object
{
private:
Bus &_bus;
Genode::Session_label const _label;
Genode::Io_signal_handler<Session_component> _packet_handler;
Mac_address const _mac { _bus.insert(_label, *this) };
Nic::Packet_stream_sink<::Nic::Session::Policy> &sink() {
return *_tx.sink(); }
Nic::Packet_stream_source<::Nic::Session::Policy> &source() {
return *_rx.source(); }
void _send(Ethernet_frame const &eth, Genode::size_t const size)
{
while (source().ack_avail())
source().release_packet(source().get_acked_packet());
Nic::Packet_descriptor pkt = source().alloc_packet(size);
void *content = source().packet_content(pkt);
Genode::memcpy(content, (void*)&eth, size);
source().submit_packet(pkt);
}
void _handle_ethernet(Ethernet_frame const &eth,
Genode::size_t const size)
{
if (eth.src() != _mac) {
Genode::warning(
eth.src(), " is not the managed MAC adress, "
"dropping packet from ", _label);
return;
}
auto send = [&] (Session_component &other) { other._send(eth, size); };
if (eth.dst().addr[0] & 1) {
_bus.apply_all(send);
} else {
_bus.apply(eth.dst(), send);
}
}
void _handle_packet(Nic::Packet_descriptor const &pkt)
{
if (!pkt.size() || !sink().packet_valid(pkt)) return;
Size_guard size_guard(pkt.size());
Ethernet_frame const &eth = Ethernet_frame::cast_from(
sink().packet_content(pkt), size_guard);
_handle_ethernet(eth, pkt.size());
}
void _handle_packets()
{
while (sink().ready_to_ack() && sink().packet_avail()) {
_handle_packet(sink().peek_packet());
sink().acknowledge_packet(sink().get_packet());
}
}
public:
Session_component(Genode::Entrypoint &ep,
Genode::Ram_allocator &ram,
Genode::Region_map &region_map,
Genode::Ram_quota ram_quota,
Genode::Cap_quota cap_quota,
Tx_size tx_size,
Rx_size rx_size,
Bus &bus,
Genode::Session_label const &label)
:
Session_resources(ram, region_map,
ram_quota, cap_quota,
tx_size, rx_size),
Nic::Session_rpc_object(region_map,
_tx_ds.cap(), _rx_ds.cap(),
&_rx_pkt_alloc, ep.rpc_ep()),
_bus(bus), _label(label),
_packet_handler(ep, *this, &Session_component::_handle_packets)
{
_tx.sigh_packet_avail(_packet_handler);
_tx.sigh_ready_to_ack(_packet_handler);
}
Nic::Mac_address mac_address() override { return _mac; }
bool link_state() override { return true; }
void link_state_sigh(Genode::Signal_context_capability) override { }
};
#endif /* _SESSION_COMPONENT_H_ */