nic_router/nic_bridge: re-work Mac_allocator

The old MAC allocator had several drawbacks:

* the address base was a public static that could and must have been written
  directly from outside the class
* the in-use-flag array was based on unsigned values consuming 4 bytes each
  for only one bit of information
* it was a public header that we actually don't want to expose to all
  components but only to the few networking components
* it used the not-so-safe bit notation for integer members of GCC

The new version fixes all these drawbacks.

Issue #2795
This commit is contained in:
Martin Stein 2018-04-27 13:38:49 +02:00 committed by Christian Helmuth
parent 980f3e9c5c
commit 41dbad13e4
8 changed files with 130 additions and 112 deletions

View File

@ -1,85 +0,0 @@
/*
* \brief MAC-address allocator
* \author Stefan Kalkowski
* \date 2010-08-25
*/
/*
* Copyright (C) 2010-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 _MAC_ALLOCATOR_H_
#define _MAC_ALLOCATOR_H_
/* Genode includes */
#include <base/exception.h>
#include <net/ethernet.h>
namespace Net {
/**
* The MAC allocator is used to administer MAC addresses for
* NIC session clients.
*/
class Mac_allocator
{
private:
/* limit available MAC addresses to one byte range */
enum { MSB_MAX = 0xFF };
/* signals, whether most significant byte is in use */
typedef struct
{
unsigned used : 1;
} Msb;
Msb _msbs[MSB_MAX]; /* bitfield of MSBs */
public:
class Alloc_failed : Genode::Exception {};
/**
* Reference MAC address
*
* We take the range 02:02:02:02:02:XX for our MAC address
* allocator, it's likely, that we will have no clashes here.
* (e.g. Linux uses 02:00... for its tap-devices.)
*/
Mac_address mac_addr_base { Mac_address(0x02) };
Mac_allocator() { Genode::memset(&_msbs, 0, sizeof(_msbs)); }
/**
* Allocates a new MAC address.
*
* \throws Alloc_failed if no more MAC addresses are available.
* \return MAC address
*/
Mac_address alloc()
{
for (int i=0; i < MSB_MAX; i++) {
if (!_msbs[i].used) {
_msbs[i].used = 1;
Mac_address mac = mac_addr_base;
mac.addr[5] = i;
return mac;
}
}
throw Alloc_failed();
}
/**
* Frees a formerly allocated MAC address.
*/
void free(Mac_address mac) {
_msbs[(unsigned)mac.addr[5]].used = 0; }
};
}
#endif /* _MAC_ALLOCATOR_H_ */

View File

@ -1,7 +1,7 @@
SRC_DIR = src/server/nic_router
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
MIRROR_FROM_REP_DIR := lib/mk/net.mk include/net include/nic_bridge src/lib/net
MIRROR_FROM_REP_DIR := lib/mk/net.mk include/net src/lib/net
content: $(MIRROR_FROM_REP_DIR)

View File

@ -14,18 +14,21 @@
#ifndef _COMPONENT_H_
#define _COMPONENT_H_
/* Genode */
/* Genode includes */
#include <base/log.h>
#include <base/heap.h>
#include <nic/packet_allocator.h>
#include <nic_session/rpc_object.h>
#include <nic_session/connection.h>
#include <nic_bridge/mac_allocator.h>
#include <os/ram_session_guard.h>
#include <os/session_policy.h>
#include <root/component.h>
#include <util/arg_string.h>
/* NIC router includes */
#include <mac_allocator.h>
/* local includes */
#include <address_node.h>
#include <nic.h>
#include <packet_handler.h>
@ -187,7 +190,9 @@ class Net::Root : public Genode::Root_component<Net::Session_component>
{
private:
Mac_allocator _mac_alloc { };
enum { DEFAULT_MAC = 0x02 };
Mac_allocator _mac_alloc;
Genode::Env &_env;
Net::Nic &_nic;
Genode::Xml_node _config;
@ -242,9 +247,8 @@ class Net::Root : public Genode::Root_component<Net::Session_component>
Root(Genode::Env &env, Net::Nic &nic, Genode::Allocator &md_alloc,
Genode::Xml_node config)
: Genode::Root_component<Session_component>(env.ep(), md_alloc),
_mac_alloc(Mac_address(config.attribute_value("mac", (Genode::uint8_t)DEFAULT_MAC))),
_env(env), _nic(nic), _config(config) { }
Mac_address &mac_addr_base() { return _mac_alloc.mac_addr_base; }
};
#endif /* _COMPONENT_H_ */

View File

@ -0,0 +1,57 @@
/*
* \brief MAC-address allocator
* \author Stefan Kalkowski
* \date 2010-08-25
*/
/*
* Copyright (C) 2010-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 _MAC_ALLOCATOR_H_
#define _MAC_ALLOCATOR_H_
/* Genode includes */
#include <base/exception.h>
#include <net/mac_address.h>
namespace Net { class Mac_allocator; }
class Net::Mac_allocator
{
private:
Mac_address const _base;
bool _free[sizeof(_base.addr[0]) << 8];
public:
struct Alloc_failed : Genode::Exception {};
Mac_allocator(Mac_address base) : _base(base)
{
Genode::memset(&_free, true, sizeof(_free));
}
Mac_address alloc()
{
for (unsigned id = 0; id < sizeof(_free) / sizeof(_free[0]); id++) {
if (!_free[id]) {
continue; }
_free[id] = false;
Mac_address mac = _base;
mac.addr[5] = id;
return mac;
}
throw Alloc_failed();
}
void free(Mac_address mac) { _free[mac.addr[5]] = true; }
};
#endif /* _MAC_ALLOCATOR_H_ */

View File

@ -35,23 +35,9 @@ struct Main
Net::Nic nic { env, heap, vlan };
Net::Root root { env, nic, heap, config.xml() };
void handle_config()
{
/* read MAC address prefix from config file */
try {
Nic::Mac_address mac;
config.xml().attribute("mac").value(&mac);
Genode::memcpy(&root.mac_addr_base(), &mac,
sizeof(Net::Mac_allocator::mac_addr_base));
} catch(...) {}
}
Main(Genode::Env &e) : env(e)
{
try {
/* read configuration file */
handle_config();
/* show MAC address to use */
Net::Mac_address mac(nic.mac());
Genode::log("--- NIC bridge started (mac=", mac, ") ---");

View File

@ -122,11 +122,10 @@ Net::Root::Root(Entrypoint &ep,
Region_map &region_map)
:
Root_component<Session_component>(&ep.rpc_ep(), &alloc), _timer(timer),
_ep(ep), _router_mac(router_mac), _config(config), _buf_ram(buf_ram),
_region_map(region_map), _interfaces(interfaces)
{
_mac_alloc.mac_addr_base = config.mac_first();
}
_mac_alloc(config.mac_first()), _ep(ep), _router_mac(router_mac),
_config(config), _buf_ram(buf_ram), _region_map(region_map),
_interfaces(interfaces)
{ }
Session_component *Net::Root::_create_session(char const *args)

View File

@ -19,9 +19,9 @@
#include <root/component.h>
#include <nic/packet_allocator.h>
#include <nic_session/rpc_object.h>
#include <nic_bridge/mac_allocator.h>
/* local includes */
#include <mac_allocator.h>
#include <interface.h>
#include <reference.h>
@ -137,7 +137,7 @@ class Net::Root : public Genode::Root_component<Session_component>
private:
Timer::Connection &_timer;
Mac_allocator _mac_alloc { };
Mac_allocator _mac_alloc;
Genode::Entrypoint &_ep;
Mac_address const _router_mac;
Reference<Configuration> _config;

View File

@ -0,0 +1,57 @@
/*
* \brief MAC-address allocator
* \author Stefan Kalkowski
* \date 2010-08-25
*/
/*
* Copyright (C) 2010-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 _MAC_ALLOCATOR_H_
#define _MAC_ALLOCATOR_H_
/* Genode includes */
#include <base/exception.h>
#include <net/mac_address.h>
namespace Net { class Mac_allocator; }
class Net::Mac_allocator
{
private:
Mac_address const _base;
bool _free[sizeof(_base.addr[0]) << 8];
public:
struct Alloc_failed : Genode::Exception {};
Mac_allocator(Mac_address base) : _base(base)
{
Genode::memset(&_free, true, sizeof(_free));
}
Mac_address alloc()
{
for (unsigned id = 0; id < sizeof(_free) / sizeof(_free[0]); id++) {
if (!_free[id]) {
continue; }
_free[id] = false;
Mac_address mac = _base;
mac.addr[5] = id;
return mac;
}
throw Alloc_failed();
}
void free(Mac_address mac) { _free[mac.addr[5]] = true; }
};
#endif /* _MAC_ALLOCATOR_H_ */