Let the nic_bridge work event driven (fix #749)

This commit is contained in:
Stefan Kalkowski 2013-05-28 13:53:03 +02:00 committed by Norman Feske
parent 153429268e
commit 853d541340
17 changed files with 605 additions and 627 deletions

View File

@ -57,6 +57,8 @@ namespace Net {
static const Ipv4_address CURRENT; /* current network */
static const Ipv4_address BROADCAST; /* broadcast address */
static Ipv4_address ip_from_string(const char *ip);
private:
/************************

View File

@ -1,3 +1,3 @@
SRC_CC = ethernet.cc
SRC_CC = ethernet.cc ipv4.cc
vpath %.cc $(REP_DIR)/src/lib/net

View File

@ -11,7 +11,57 @@
* under the terms of the GNU General Public License version 2.
*/
#include <util/token.h>
#include <util/string.h>
#include <net/ipv4.h>
const Net::Ipv4_packet::Ipv4_address Net::Ipv4_packet::CURRENT(0x00);
const Net::Ipv4_packet::Ipv4_address Net::Ipv4_packet::BROADCAST(0xFF);
using namespace Net;
struct Scanner_policy_number
{
static bool identifier_char(char c, unsigned i ) {
return Genode::is_digit(c) && c !='.'; }
};
typedef ::Genode::Token<Scanner_policy_number> Token;
Ipv4_packet::Ipv4_address Ipv4_packet::ip_from_string(const char *ip)
{
Ipv4_address ip_addr;
Token t(ip);
char tmpstr[4];
int cnt = 0;
unsigned char ipb[4] = {0};
while(t) {
if (t.type() == Token::WHITESPACE || t[0] == '.') {
t = t.next();
continue;
}
t.string(tmpstr, sizeof(tmpstr));
unsigned long tmpc = 0;
Genode::ascii_to(tmpstr, &tmpc, 10);
ipb[cnt] = tmpc & 0xFF;
t = t.next();
if (cnt == 4)
break;
cnt++;
}
if (cnt == 4) {
ip_addr.addr[0] = ipb[0];
ip_addr.addr[1] = ipb[1];
ip_addr.addr[2] = ipb[2];
ip_addr.addr[3] = ipb[3];
}
return ip_addr;
}
const Ipv4_packet::Ipv4_address Ipv4_packet::CURRENT((Genode::uint8_t)0x00);
const Ipv4_packet::Ipv4_address Ipv4_packet::BROADCAST((Genode::uint8_t)0xFF);

View File

@ -1,55 +0,0 @@
/*
* \brief Address-node holds a client-specific session-component.
* \author Stefan Kalkowski
* \date 2010-08-25
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/lock_guard.h>
#include "address_node.h"
#include "component.h"
/**
* Let the client a receive a network packet.
*
* \param addr start address network packet.
* \param size size of network packet.
*/
template <unsigned LEN>
void Net::Address_node<LEN>::receive_packet(void *addr, Genode::size_t size)
{
Genode::Lock::Guard lock_guard(*_component->rx_lock());
Nic::Session::Rx::Source *source = _component->rx_source();
while (true) {
/* flush remaining acknowledgements */
while (source->ack_avail())
source->release_packet(source->get_acked_packet());
try {
/* allocate packet in rx channel */
Packet_descriptor rx_packet = source->alloc_packet(size);
Genode::memcpy((void*)source->packet_content(rx_packet),
(void*)addr, size);
source->submit_packet(rx_packet);
return;
} catch (Nic::Session::Rx::Source::Packet_alloc_failed) { }
}
}
/**
* Let the compiler know, for which template instances this implementation
* is used for.
*/
template void Net::Ipv4_address_node::receive_packet(void *addr, Genode::size_t size);
template void Net::Mac_address_node::receive_packet(void *addr, Genode::size_t size);

View File

@ -65,14 +65,6 @@ namespace Net {
Address addr() { return _addr; }
Session_component *component() { return _component; }
/**
* Let this client node, receive a network-packet
*
* \param addr start address of network packet
* \param size size of network packet
*/
void receive_packet(void *addr, Genode::size_t size);
/************************
** Avl node interface **

View File

@ -16,44 +16,17 @@
#include <net/dhcp.h>
#include <net/udp.h>
#include <util/token.h>
#include <util/string.h>
#include "env.h"
#include "component.h"
#include "nic.h"
#include "vlan.h"
using namespace Net;
const int Session_component::verbose = 1;
void Session_component::Tx_handler::acknowledge_last_one()
{
if (!_tx_packet.valid())
return;
if (!_component->tx_sink()->ready_to_ack())
PDBG("need to wait until ready-for-ack");
_component->tx_sink()->acknowledge_packet(_tx_packet);
}
static const int verbose = 1;
void Session_component::Tx_handler::next_packet(void** src, Genode::size_t *size)
{
while (true) {
/* block for a new packet */
_tx_packet = _component->tx_sink()->get_packet();
if (!_tx_packet.valid()) {
PWRN("received invalid packet");
continue;
}
*src = _component->tx_sink()->packet_content(_tx_packet);
*size = _tx_packet.size();
return;
}
}
bool Session_component::Tx_handler::handle_arp(Ethernet_frame *eth, Genode::size_t size)
bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
{
Arp_packet *arp =
new (eth->data()) Arp_packet(size - sizeof(Ethernet_frame));
@ -71,18 +44,18 @@ bool Session_component::Tx_handler::handle_arp(Ethernet_frame *eth, Genode::size
if (arp->src_ip() == arp->dst_ip())
return false;
Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first();
Ipv4_address_node *node = Env::vlan()->ip_tree()->first();
if (node)
node = node->find_by_address(arp->dst_ip());
if (!node) {
arp->src_mac(_mac);
arp->src_mac(Net::Env::nic()->mac());
}
}
return true;
}
bool Session_component::Tx_handler::handle_ip(Ethernet_frame *eth, Genode::size_t size)
bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size)
{
Ipv4_packet *ip =
new (eth->data()) Ipv4_packet(size - sizeof(Ethernet_frame));
@ -104,137 +77,84 @@ bool Session_component::Tx_handler::handle_ip(Ethernet_frame *eth, Genode::size_
}
void Session_component::Tx_handler::finalize_packet(Ethernet_frame *eth,
void Session_component::finalize_packet(Ethernet_frame *eth,
Genode::size_t size)
{
Mac_address_node *node = Vlan::vlan()->mac_tree()->first();
Mac_address_node *node = Env::vlan()->mac_tree()->first();
if (node)
node = node->find_by_address(eth->dst());
if (node)
node->receive_packet((void*) eth, size);
else
send_to_nic(eth, size);
node->component()->send(eth, size);
else {
/* set our MAC as sender */
eth->src(Net::Env::nic()->mac());
Net::Env::nic()->send(eth, size);
}
}
void Session_component::_free_ipv4_node()
{
if (_ipv4_node) {
Vlan::vlan()->ip_tree()->remove(_ipv4_node);
Env::vlan()->ip_tree()->remove(_ipv4_node);
destroy(this->guarded_allocator(), _ipv4_node);
}
}
struct Scanner_policy_number
{
static bool identifier_char(char c, unsigned i )
{
return Genode::is_digit(c) && c !='.';
}
};
typedef ::Genode::Token<Scanner_policy_number> Token;
Ipv4_packet::Ipv4_address Session_component::ip_from_string(const char *ip)
{
Ipv4_packet::Ipv4_address ip_addr;
Token t(ip);
char tmpstr[4];
int cnt = 0;
unsigned char ipb[4] = {0};
while(t) {
if (t.type() == Token::WHITESPACE || t[0] == '.') {
t = t.next();
continue;
}
t.string(tmpstr, sizeof(tmpstr));
unsigned long tmpc = 0;
Genode::ascii_to(tmpstr, &tmpc, 10);
ipb[cnt] = tmpc & 0xFF;
t = t.next();
if (cnt == 4)
break;
cnt++;
}
if (cnt == 4) {
ip_addr.addr[0] = ipb[0];
ip_addr.addr[1] = ipb[1];
ip_addr.addr[2] = ipb[2];
ip_addr.addr[3] = ipb[3];
}
return ip_addr;
}
Session_component::Session_component(Genode::Allocator *allocator,
Genode::size_t amount,
Genode::size_t tx_buf_size,
Genode::size_t rx_buf_size,
Ethernet_frame::Mac_address vmac,
Nic::Connection *session,
Genode::Rpc_entrypoint &ep,
char *ip_addr)
: Guarded_range_allocator(allocator, amount),
Tx_rx_communication_buffers(tx_buf_size, rx_buf_size),
Session_rpc_object(Tx_rx_communication_buffers::tx_ds(),
Tx_rx_communication_buffers::rx_ds(),
this->range_allocator(), ep),
_tx_handler(session, this),
_mac_node(vmac, this),
_ipv4_node(0)
{
Vlan::vlan()->mac_tree()->insert(&_mac_node);
Vlan::vlan()->mac_list()->insert(&_mac_node);
/* start handler */
_tx_handler.start();
_tx_handler.wait_for_startup();
/* static ip parsing */
if (ip_addr != 0 && Genode::strlen(ip_addr)) {
Ipv4_packet::Ipv4_address ip = ip_from_string(ip_addr);
if (ip == Ipv4_packet::Ipv4_address()) {
PDBG("Empty or error ip address. Skipped.");
} else {
set_ipv4_address(ip);
if (verbose)
PDBG("\nmac=%02x.%02x.%02x.%02x.%02x.%02x ip=%d.%d.%d.%d",
vmac.addr[0], vmac.addr[1], vmac.addr[2], vmac.addr[3], vmac.addr[4], vmac.addr[5],
ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3]
);
}
}
}
Session_component::~Session_component() {
Vlan::vlan()->mac_tree()->remove(&_mac_node);
Vlan::vlan()->mac_list()->remove(&_mac_node);
_free_ipv4_node();
}
void Session_component::set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr)
{
_free_ipv4_node();
_ipv4_node = new (this->guarded_allocator())
Ipv4_address_node(ip_addr, this);
Vlan::vlan()->ip_tree()->insert(_ipv4_node);
Net::Env::vlan()->ip_tree()->insert(_ipv4_node);
}
Session_component::Session_component(Genode::Allocator *allocator,
Genode::size_t amount,
Genode::size_t tx_buf_size,
Genode::size_t rx_buf_size,
Ethernet_frame::Mac_address vmac,
Genode::Rpc_entrypoint &ep,
char *ip_addr)
: Guarded_range_allocator(allocator, amount),
Tx_rx_communication_buffers(tx_buf_size, rx_buf_size),
Session_rpc_object(Tx_rx_communication_buffers::tx_ds(),
Tx_rx_communication_buffers::rx_ds(),
this->range_allocator(), ep),
_mac_node(vmac, this),
_ipv4_node(0)
{
Env::vlan()->mac_tree()->insert(&_mac_node);
Env::vlan()->mac_list()->insert(&_mac_node);
/* static ip parsing */
if (ip_addr != 0 && Genode::strlen(ip_addr)) {
Ipv4_packet::Ipv4_address ip = Ipv4_packet::ip_from_string(ip_addr);
if (ip == Ipv4_packet::Ipv4_address()) {
PWRN("Empty or error ip address. Skipped.");
} else {
set_ipv4_address(ip);
if (verbose)
PDBG("\nmac=%02x.%02x.%02x.%02x.%02x.%02x ip=%d.%d.%d.%d",
vmac.addr[0], vmac.addr[1], vmac.addr[2],
vmac.addr[3], vmac.addr[4], vmac.addr[5],
ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3]);
}
}
_tx.sigh_ready_to_ack(_sink_ack);
_tx.sigh_packet_avail(_sink_submit);
_rx.sigh_ack_avail(_source_ack);
_rx.sigh_ready_to_submit(_source_submit);
}
Session_component::~Session_component() {
Env::vlan()->mac_tree()->remove(&_mac_node);
Env::vlan()->mac_list()->remove(&_mac_node);
_free_ipv4_node();
}

View File

@ -40,7 +40,7 @@ namespace Net {
private:
Genode::Allocator_guard _guarded_alloc;
Nic::Packet_allocator _range_alloc;
::Nic::Packet_allocator _range_alloc;
public:
@ -97,41 +97,15 @@ namespace Net {
*/
class Session_component : public Guarded_range_allocator,
private Tx_rx_communication_buffers,
public Nic::Session_rpc_object
public ::Nic::Session_rpc_object,
public Packet_handler
{
private:
class Tx_handler : public Packet_handler
{
private:
Packet_descriptor _tx_packet;
Session_component *_component;
void acknowledge_last_one();
void next_packet(void** src, Genode::size_t *size);
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
void finalize_packet(Ethernet_frame *eth, Genode::size_t size);
public:
Tx_handler(Nic::Connection *session,
Session_component *component)
: Packet_handler(session), _component(component) {}
};
Tx_handler _tx_handler;
Mac_address_node _mac_node;
Ipv4_address_node *_ipv4_node;
Genode::Lock _rx_lock;
static const int verbose;
void _free_ipv4_node();
Ipv4_packet::Ipv4_address ip_from_string(const char *ip);
public:
@ -150,25 +124,34 @@ namespace Net {
Genode::size_t tx_buf_size,
Genode::size_t rx_buf_size,
Ethernet_frame::Mac_address vmac,
Nic::Connection *session,
Genode::Rpc_entrypoint &ep,
char *ip_addr = 0);
~Session_component();
Nic::Session::Tx::Sink* tx_sink() { return _tx.sink(); }
Nic::Session::Rx::Source* rx_source() { return _rx.source(); }
Genode::Lock* rx_lock() { return &_rx_lock; }
Nic::Mac_address mac_address()
::Nic::Mac_address mac_address()
{
Nic::Mac_address m;
::Nic::Mac_address m;
Mac_address_node::Address mac = _mac_node.addr();
Genode::memcpy(&m, mac.addr, sizeof(m.addr));
return m;
}
void set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr);
/******************************
** Packet_handler interface **
******************************/
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
return _tx.sink(); }
Packet_stream_source< ::Nic::Session::Policy> * source() {
return _rx.source(); }
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
void finalize_packet(Ethernet_frame *eth, Genode::size_t size);
};
@ -182,7 +165,6 @@ namespace Net {
enum { verbose = 1 };
Mac_allocator _mac_alloc;
Nic::Connection *_session;
Genode::Rpc_entrypoint &_ep;
protected:
@ -240,10 +222,8 @@ namespace Net {
tx_buf_size,
rx_buf_size,
_mac_alloc.alloc(),
_session,
_ep,
ip_addr
);
ip_addr);
} catch(Mac_allocator::Alloc_failed) {
PWRN("Mac address allocation failed!");
return (Session_component*) 0;
@ -253,10 +233,9 @@ namespace Net {
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc,
Nic::Connection *session)
Genode::Allocator *md_alloc)
: Genode::Root_component<Session_component>(session_ep, md_alloc),
_session(session), _ep(*session_ep) { }
_ep(*session_ep) { }
};
} /* namespace Net */

View File

@ -0,0 +1,36 @@
/*
* \brief Nic-bridge global environment
* \author Stefan Kalkowski
* \date 2013-05-23
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "env.h"
#include "nic.h"
#include "vlan.h"
Genode::Signal_receiver* Net::Env::receiver()
{
static Genode::Signal_receiver receiver;
return &receiver;
}
Net::Vlan* Net::Env::vlan()
{
static Net::Vlan vlan;
return &vlan;
}
Net::Nic* Net::Env::nic()
{
static Net::Nic nic;
return &nic;
}

View File

@ -0,0 +1,36 @@
/*
* \brief Proxy-ARP environment
* \author Stefan Kalkowski
* \date 2013-05-24
*
* A database containing all clients sorted by IP and MAC addresses.
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SRC__SERVER__NIC_BRIDGE__ENV_H_
#define _SRC__SERVER__NIC_BRIDGE__ENV_H_
#include <base/signal.h>
namespace Net {
class Vlan;
class Nic;
class Env;
}
struct Net::Env
{
static Genode::Signal_receiver* receiver();
static Vlan *vlan();
static Net::Nic *nic();
};
#endif /* _SRC__SERVER__NIC_BRIDGE__ENV_H_ */

View File

@ -13,32 +13,21 @@
/* Genode */
#include <base/env.h>
#include <base/sleep.h>
#include <cap_session/connection.h>
#include <nic_session/connection.h>
#include <nic/packet_allocator.h>
#include <nic/xml_node.h>
#include <os/config.h>
#include "packet_handler.h"
/* local includes */
#include "component.h"
#include "env.h"
int main(int, char **)
{
using namespace Genode;
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_bridge_ep");
static Nic::Packet_allocator tx_block_alloc(env()->heap());
enum {
PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE,
};
/* read MAC address prefix from config file */
try {
Nic::Mac_address mac;
@ -47,23 +36,22 @@ int main(int, char **)
sizeof(Net::Mac_allocator::mac_addr_base));
} catch(...) {}
Root_capability nic_root_cap;
try {
static Nic::Connection nic(&tx_block_alloc, BUF_SIZE, BUF_SIZE);
static Net::Rx_handler rx_handler(&nic);
static Net::Root nic_root(&ep, env()->heap(), &nic);
/* start receiver thread handling packets from the NIC driver */
rx_handler.start();
rx_handler.wait_for_startup();
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_bridge_ep");
static Net::Root nic_root(&ep, env()->heap());
/* announce NIC service */
env()->parent()->announce(ep.manage(&nic_root));
while (true) {
Signal s = Net::Env::receiver()->wait_for_signal();
static_cast<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
}
} catch (Parent::Service_denied) {
PERR("Could not connect to uplink NIC");
}
sleep_forever();
return 0;
}

View File

@ -0,0 +1,136 @@
/*
* \brief NIC handler
* \author Stefan Kalkowski
* \date 2013-05-24
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <net/ethernet.h>
#include <net/arp.h>
#include <net/ipv4.h>
#include <net/udp.h>
#include <net/dhcp.h>
#include "address_node.h"
#include "component.h"
#include "env.h"
#include "nic.h"
#include "vlan.h"
using namespace Net;
bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
Arp_packet *arp = new (eth->data())
Arp_packet(size - sizeof(Ethernet_frame));
/* ignore broken packets */
if (!arp->ethernet_ipv4())
return true;
/* look whether the IP address is one of our client's */
Ipv4_address_node *node = Env::vlan()->ip_tree()->first();
if (node)
node = node->find_by_address(arp->dst_ip());
if (node) {
if (arp->opcode() == Arp_packet::REQUEST) {
/*
* The ARP packet gets re-written, we interchange source
* and destination MAC and IP addresses, and set the opcode
* to reply, and then push the packet back to the NIC driver.
*/
Ipv4_packet::Ipv4_address old_src_ip = arp->src_ip();
arp->opcode(Arp_packet::REPLY);
arp->dst_mac(arp->src_mac());
arp->src_mac(mac());
arp->src_ip(arp->dst_ip());
arp->dst_ip(old_src_ip);
eth->dst(arp->dst_mac());
/* set our MAC as sender */
eth->src(mac());
send(eth, size);
} else {
/* overwrite destination MAC */
arp->dst_mac(node->component()->mac_address().addr);
eth->dst(node->component()->mac_address().addr);
node->component()->send(eth, size);
}
return false;
}
return true;
}
bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
Ipv4_packet *ip = new (eth->data())
Ipv4_packet(size - sizeof(Ethernet_frame));
/* is it an UDP packet ? */
if (ip->protocol() == Udp_packet::IP_ID)
{
Udp_packet *udp = new (ip->data())
Udp_packet(size - sizeof(Ipv4_packet));
/* is it a DHCP packet ? */
if (Dhcp_packet::is_dhcp(udp)) {
Dhcp_packet *dhcp = new (udp->data())
Dhcp_packet(size - sizeof(Ipv4_packet) - sizeof(Udp_packet));
/* check for DHCP ACKs containing new client ips */
if (dhcp->op() == Dhcp_packet::REPLY) {
Dhcp_packet::Option *ext = dhcp->option(Dhcp_packet::MSG_TYPE);
if (ext) {
/*
* extract the IP address and set it in the
* client's session-component
*/
Genode::uint8_t *msg_type = (Genode::uint8_t*) ext->value();
if (*msg_type == Dhcp_packet::DHCP_ACK) {
Mac_address_node *node =
Env::vlan()->mac_tree()->first();
if (node)
node = node->find_by_address(dhcp->client_mac());
if (node)
node->component()->set_ipv4_address(dhcp->yiaddr());
}
}
}
}
}
/* is it an unicast message to one of our clients ? */
if (eth->dst() == Net::Env::nic()->mac()) {
Ipv4_address_node *node = Env::vlan()->ip_tree()->first();
if (node) {
node = node->find_by_address(ip->dst());
if (node) {
/* overwrite destination MAC */
eth->dst(node->component()->mac_address().addr);
/* deliver the packet to the client */
node->component()->send(eth, size);
return false;
}
}
}
return true;
}
Net::Nic::Nic()
: _tx_block_alloc(Genode::env()->heap()),
_nic(&_tx_block_alloc, BUF_SIZE, BUF_SIZE)
{
_nic.rx_channel()->sigh_ready_to_ack(_sink_ack);
_nic.rx_channel()->sigh_packet_avail(_sink_submit);
_nic.tx_channel()->sigh_ack_avail(_source_ack);
_nic.tx_channel()->sigh_ready_to_submit(_source_submit);
}

View File

@ -0,0 +1,64 @@
/*
* \brief Proxy-ARP NIC session handler
* \author Stefan Kalkowski
* \date 2010-08-18
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SRC__SERVER__NIC_BRIDGE__NIC_H_
#define _SRC__SERVER__NIC_BRIDGE__NIC_H_
#include <nic_session/connection.h>
#include <nic/packet_allocator.h>
#include "env.h"
#include "packet_handler.h"
namespace Net {
class Nic;
}
class Net::Nic : public Net::Packet_handler
{
private:
enum {
PACKET_SIZE = ::Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
BUF_SIZE = ::Nic::Session::QUEUE_SIZE * PACKET_SIZE,
};
::Nic::Packet_allocator _tx_block_alloc;
::Nic::Connection _nic;
public:
Nic();
::Nic::Connection *nic() { return &_nic; }
Ethernet_frame::Mac_address mac() { return _nic.mac_address().addr; }
/******************************
** Packet_handler interface **
******************************/
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
return _nic.rx(); }
Packet_stream_source< ::Nic::Session::Policy> * source() {
return _nic.tx(); }
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
void finalize_packet(Ethernet_frame *eth, Genode::size_t size) {}
};
#endif /* _SRC__SERVER__NIC_BRIDGE__NIC_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Thread implementations handling network packets.
* \brief Packet handler handling network packets.
* \author Stefan Kalkowski
* \date 2010-08-18
*/
@ -18,14 +18,40 @@
#include <net/ipv4.h>
#include <net/udp.h>
#include "env.h"
#include "component.h"
#include "packet_handler.h"
#include "vlan.h"
using namespace Net;
static const bool verbose = true;
static Genode::Lock _nic_lock;
void Packet_handler::_ready_to_submit(unsigned)
{
/* as long as packets are available, and we can ack them */
while (sink()->packet_avail()) {
_packet = sink()->get_packet();
if (!_packet.valid()) continue;
handle_ethernet(sink()->packet_content(_packet), _packet.size());
if (!sink()->ready_to_ack()) {
if (verbose)
PWRN("ack state FULL");
return;
}
sink()->acknowledge_packet(_packet);
}
}
void Packet_handler::_ready_to_ack(unsigned)
{
/* check for acknowledgements */
while (source()->ack_avail())
source()->release_packet(source()->get_acked_packet());
}
void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t size)
@ -34,202 +60,66 @@ void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t si
if (eth->dst() == Ethernet_frame::BROADCAST) {
/* iterate through the list of clients */
Mac_address_node *node =
Vlan::vlan()->mac_list()->first();
Env::vlan()->mac_list()->first();
while (node) {
/* deliver packet */
node->receive_packet((void*) eth, size);
node->component()->send(eth, size);
node = node->next();
}
}
}
void Packet_handler::send_to_nic(Ethernet_frame *eth, Genode::size_t size)
void Packet_handler::handle_ethernet(void* src, Genode::size_t size)
{
Genode::Lock::Guard lock_guard(_nic_lock);
while (true) {
/* check for acknowledgements */
while (_session->tx()->ack_avail()) {
Packet_descriptor p =
_session->tx()->get_acked_packet();
_session->tx()->release_packet(p);
try {
/* parse ethernet frame header */
Ethernet_frame *eth = new (src) Ethernet_frame(size);
switch (eth->type()) {
case Ethernet_frame::ARP:
if (!handle_arp(eth, size)) return;
break;
case Ethernet_frame::IPV4:
if(!handle_ip(eth, size)) return;
break;
default:
;
}
try {
/* set our MAC as sender */
eth->src(_mac);
/* allocate packet to NIC driver */
Packet_descriptor tx_packet = _session->tx()->alloc_packet(size);
char *tx_content = _session->tx()->packet_content(tx_packet);
/* copy and submit packet */
Genode::memcpy((void*)tx_content, (void*)eth, size);
_session->tx()->submit_packet(tx_packet);
return;
} catch(Nic::Session::Tx::Source::Packet_alloc_failed) { }
broadcast_to_clients(eth, size);
finalize_packet(eth, size);
} catch(Arp_packet::No_arp_packet) {
PWRN("Invalid ARP packet!");
} catch(Ethernet_frame::No_ethernet_frame) {
PWRN("Invalid ethernet frame");
} catch(Dhcp_packet::No_dhcp_packet) {
PWRN("Invalid IPv4 packet!");
} catch(Ipv4_packet::No_ip_packet) {
PWRN("Invalid IPv4 packet!");
} catch(Udp_packet::No_udp_packet) {
PWRN("Invalid UDP packet!");
}
}
void Packet_handler::entry()
void Packet_handler::send(Ethernet_frame *eth, Genode::size_t size)
{
void* src;
Genode::size_t eth_sz;
/* signal preparedness */
_startup_sem.up();
/* loop for new packets */
while (true) {
try {
acknowledge_last_one();
next_packet(&src, &eth_sz);
/* parse ethernet frame header */
Ethernet_frame *eth = new (src) Ethernet_frame(eth_sz);
switch (eth->type()) {
case Ethernet_frame::ARP:
{
if (!handle_arp(eth, eth_sz))
continue;
break;
}
case Ethernet_frame::IPV4:
{
if(!handle_ip(eth, eth_sz))
continue;
break;
}
default:
;
}
/* broadcast packet ? */
broadcast_to_clients(eth, eth_sz);
finalize_packet(eth, eth_sz);
} catch(Arp_packet::No_arp_packet) {
PWRN("Invalid ARP packet!");
} catch(Ethernet_frame::No_ethernet_frame) {
PWRN("Invalid ethernet frame");
} catch(Dhcp_packet::No_dhcp_packet) {
PWRN("Invalid IPv4 packet!");
} catch(Ipv4_packet::No_ip_packet) {
PWRN("Invalid IPv4 packet!");
} catch(Udp_packet::No_udp_packet) {
PWRN("Invalid UDP packet!");
}
try {
/* copy and submit packet */
Packet_descriptor packet = source()->alloc_packet(size);
char *content = source()->packet_content(packet);
Genode::memcpy((void*)content, (void*)eth, size);
source()->submit_packet(packet);
} catch(Packet_stream_source< ::Nic::Session::Policy>::Packet_alloc_failed) {
if (verbose)
PWRN("Packet dropped");
}
}
void Rx_handler::acknowledge_last_one() {
/* acknowledge packet to NIC driver */
if(_rx_packet.valid())
_session->rx()->acknowledge_packet(_rx_packet);
}
void Rx_handler::next_packet(void** src, Genode::size_t *size) {
/* get next packet from NIC driver */
_rx_packet = _session->rx()->get_packet();
*src = _session->rx()->packet_content(_rx_packet);
*size = _rx_packet.size();
}
bool Rx_handler::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
Arp_packet *arp = new (eth->data())
Arp_packet(size - sizeof(Ethernet_frame));
/* ignore broken packets */
if (!arp->ethernet_ipv4())
return true;
/* look whether the IP address is one of our client's */
Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first();
if (node)
node = node->find_by_address(arp->dst_ip());
if (node) {
if (arp->opcode() == Arp_packet::REQUEST) {
/*
* The ARP packet gets re-written, we interchange source
* and destination MAC and IP addresses, and set the opcode
* to reply, and then push the packet back to the NIC driver.
*/
Ipv4_packet::Ipv4_address old_src_ip = arp->src_ip();
arp->opcode(Arp_packet::REPLY);
arp->dst_mac(arp->src_mac());
arp->src_mac(_mac);
arp->src_ip(arp->dst_ip());
arp->dst_ip(old_src_ip);
eth->dst(arp->dst_mac());
send_to_nic(eth, size);
} else {
/* overwrite destination MAC */
arp->dst_mac(node->component()->mac_address().addr);
eth->dst(node->component()->mac_address().addr);
node->receive_packet((void*) eth, size);
}
return false;
}
return true;
}
bool Rx_handler::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
Ipv4_packet *ip = new (eth->data())
Ipv4_packet(size - sizeof(Ethernet_frame));
/* is it an UDP packet ? */
if (ip->protocol() == Udp_packet::IP_ID)
{
Udp_packet *udp = new (ip->data())
Udp_packet(size - sizeof(Ipv4_packet));
/* is it a DHCP packet ? */
if (Dhcp_packet::is_dhcp(udp)) {
Dhcp_packet *dhcp = new (udp->data())
Dhcp_packet(size - sizeof(Ipv4_packet) - sizeof(Udp_packet));
/* check for DHCP ACKs containing new client ips */
if (dhcp->op() == Dhcp_packet::REPLY) {
Dhcp_packet::Option *ext = dhcp->option(Dhcp_packet::MSG_TYPE);
if (ext) {
/*
* extract the IP address and set it in the
* client's session-component
*/
Genode::uint8_t *msg_type = (Genode::uint8_t*) ext->value();
if (*msg_type == Dhcp_packet::DHCP_ACK) {
Mac_address_node *node =
Vlan::vlan()->mac_tree()->first();
if (node)
node = node->find_by_address(dhcp->client_mac());
if (node)
node->component()->set_ipv4_address(dhcp->yiaddr());
}
}
}
}
}
/* is it an unicast message to one of our clients ? */
if (eth->dst() == _mac) {
Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first();
if (node) {
node = node->find_by_address(ip->dst());
if (node) {
/* overwrite destination MAC */
eth->dst(node->component()->mac_address().addr);
/* deliver the packet to the client */
node->receive_packet((void*) eth, size);
return false;
}
}
}
return true;
}
Packet_handler::Packet_handler()
: _sink_ack(*Net::Env::receiver(), *this, &Packet_handler::_ack_avail),
_sink_submit(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_submit),
_source_ack(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_ack),
_source_submit(*Net::Env::receiver(), *this, &Packet_handler::_packet_avail)
{ }

View File

@ -1,5 +1,5 @@
/*
* \brief Thread implementations handling network packets.
* \brief Signal driven NIC packet handler
* \author Stefan Kalkowski
* \date 2010-08-18
*/
@ -22,147 +22,111 @@
#include <net/ipv4.h>
namespace Net {
/**
* Generic thread-implementation used as base for
* global receiver thread and client's transmit-threads.
*/
class Packet_handler : public Genode::Thread<8192>
{
private:
Genode::Semaphore _startup_sem; /* thread startup sync */
protected:
Nic::Connection *_session; /* session to nic driver */
Ethernet_frame::Mac_address _mac; /* real nic's mac */
/**
* Broadcasts ethernet frame to all clients,
* as long as its really a broadcast packtet.
*
* \param eth ethernet frame to send.
* \param size ethernet frame's size.
*/
void inline broadcast_to_clients(Ethernet_frame *eth,
Genode::size_t size);
/**
* Send ethernet frame to NIC driver.
*
* \param eth ethernet frame to send.
* \param size ethernet frame's size.
*/
void send_to_nic(Ethernet_frame *eth, Genode::size_t size);
/**
* Acknowledge the last processed packet.
*/
virtual void acknowledge_last_one() = 0;
/**
* Block for the next packet to process.
*/
virtual void next_packet(void** src,
Genode::size_t *size) = 0;
/*
* Handle an ARP packet
*
* \param eth ethernet frame containing the ARP packet.
* \param size ethernet frame's size.
*/
virtual bool handle_arp(Ethernet_frame *eth,
Genode::size_t size) = 0;
/*
* Handle an IP packet
*
* \param eth ethernet frame containing the IP packet.
* \param size ethernet frame's size.
*/
virtual bool handle_ip(Ethernet_frame *eth,
Genode::size_t size) = 0;
/*
* Finalize handling of ethernet frame.
*
* \param eth ethernet frame to handle.
* \param size ethernet frame's size.
*/
virtual void finalize_packet(Ethernet_frame *eth,
Genode::size_t size) {}
public:
Packet_handler(Nic::Connection *session)
: _session(session), _mac(session->mac_address().addr) {}
/*
* Thread's entry code.
*/
void entry();
/*
* Block until thread is ready to execute.
*/
void wait_for_startup() { _startup_sem.down(); }
};
/**
* Receiver thread handling network packets from the NIC driver
*/
class Rx_handler : public Packet_handler
{
private:
Packet_descriptor _rx_packet; /* actual processed packet */
/**
* Acknowledge the last processed packet.
*/
void acknowledge_last_one();
/**
* Block for the next packet to process.
*
* \param src buffer the network packet gets written to.
* \param size size of packet gets written to.
*/
void next_packet(void** src, Genode::size_t *size);
/*
* Handle an ARP packet.
* If it's an ARP request for an IP of one of our client's,
* reply directly with the NIC's MAC address.
*
* \param eth ethernet frame containing the ARP packet.
* \param size ethernet frame's size.
*/
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
/*
* Handle an IP packet.
* IP packets have to be inspected for DHCP replies.
* If an reply contains a new IP address for one of our
* client's, the client's database needs to be updated.
*
* \param eth ethernet frame containing the IP packet.
* \param size ethernet frame's size.
*/
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
public:
/**
* Constructor
*
* \param session session to NIC driver.
*/
Rx_handler(Nic::Connection *session) : Packet_handler(session) {}
};
class Packet_handler;
}
/**
* Generic packet handler used as base for NIC and client packet handlers.
*/
class Net::Packet_handler
{
private:
Packet_descriptor _packet;
/**
* submit queue not empty anymore
*/
void _ready_to_submit(unsigned);
/**
* acknoledgement queue not full anymore
*
* TODO: by now, we assume ACK and SUBMIT queue to be equally
* dimensioned. That's why we ignore this signal by now.
*/
void _ack_avail(unsigned) { }
/**
* acknoledgement queue not empty anymore
*/
void _ready_to_ack(unsigned);
/**
* submit queue not full anymore
*
* TODO: by now, we just drop packets that cannot be transferred
* to the other side, that's why we ignore this signal.
*/
void _packet_avail(unsigned) { }
protected:
Genode::Signal_dispatcher<Packet_handler> _sink_ack;
Genode::Signal_dispatcher<Packet_handler> _sink_submit;
Genode::Signal_dispatcher<Packet_handler> _source_ack;
Genode::Signal_dispatcher<Packet_handler> _source_submit;
public:
Packet_handler();
virtual Packet_stream_sink< ::Nic::Session::Policy> * sink() = 0;
virtual Packet_stream_source< ::Nic::Session::Policy> * source() = 0;
/**
* Broadcasts ethernet frame to all clients,
* as long as its really a broadcast packtet.
*
* \param eth ethernet frame to send.
* \param size ethernet frame's size.
*/
void inline broadcast_to_clients(Ethernet_frame *eth,
Genode::size_t size);
/**
* Send ethernet frame
*
* \param eth ethernet frame to send.
* \param size ethernet frame's size.
*/
void send(Ethernet_frame *eth, Genode::size_t size);
/**
* Handle an ethernet packet
*
* \param src ethernet frame's address
* \param size ethernet frame's size.
*/
void handle_ethernet(void* src, Genode::size_t size);
/*
* Handle an ARP packet
*
* \param eth ethernet frame containing the ARP packet.
* \param size ethernet frame's size.
*/
virtual bool handle_arp(Ethernet_frame *eth,
Genode::size_t size) = 0;
/*
* Handle an IP packet
*
* \param eth ethernet frame containing the IP packet.
* \param size ethernet frame's size.
*/
virtual bool handle_ip(Ethernet_frame *eth,
Genode::size_t size) = 0;
/*
* Finalize handling of ethernet frame.
*
* \param eth ethernet frame to handle.
* \param size ethernet frame's size.
*/
virtual void finalize_packet(Ethernet_frame *eth,
Genode::size_t size) = 0;
};
#endif /* _PACKET_HANDLER_H_ */

View File

@ -1,6 +1,5 @@
TARGET = nic_bridge
LIBS = base net
SRC_CC = address_node.cc component.cc mac.cc \
main.cc packet_handler.cc vlan.cc
SRC_CC = component.cc env.cc mac.cc main.cc nic.cc packet_handler.cc
vpath *.cc $(REP_DIR)/src/server/proxy_arp

View File

@ -1,20 +0,0 @@
/*
* \brief Virtual local network.
* \author Stefan Kalkowski
* \date 2010-08-18
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "vlan.h"
Net::Vlan* Net::Vlan::vlan()
{
static Net::Vlan vlan;
return &vlan;
}

View File

@ -40,17 +40,14 @@ namespace Net {
Mac_address_list _mac_list;
Ipv4_address_tree _ip_tree;
Vlan() {}
public:
Vlan() {}
Mac_address_tree *mac_tree() { return &_mac_tree; }
Mac_address_list *mac_list() { return &_mac_list; }
Ipv4_address_tree *ip_tree() { return &_ip_tree; }
static Vlan *vlan();
};
}
#endif /* _VLAN_H_ */