nic session: link-state change handling

A Nic::Session client can install a signal handler that is used to
propagate changes of the link-state by calling 'link_state_sigh()'.
The actual link state is queried via 'link_state()'.

The nic-driver interface now provides a Driver_notification callback,
which is used to forward link-state changes from the driver to the
Nic::Session_component.

The following drivers now provide real link state: dde_ipxe, nic_bridge,
and usb_drv. Currently, OpenVPN, Linux nic_drv, and lan9118 do not
support link state and always report link up.

Fixes #1327
This commit is contained in:
Josef Söntgen
2015-03-11 11:33:03 +01:00
committed by Christian Helmuth
parent e4f6fca355
commit dd47129bef
21 changed files with 314 additions and 67 deletions

View File

@ -32,29 +32,32 @@ namespace Ipxe {
static Driver *instance;
static void dde_rx_handler(unsigned if_index,
const char *packet,
unsigned packet_len)
private:
Nic::Mac_address _mac_addr;
Nic::Rx_buffer_alloc &_alloc;
Nic::Driver_notification &_notify;
static void _rx_callback(unsigned if_index,
const char *packet,
unsigned packet_len)
{
instance->rx_handler(packet, packet_len);
}
private:
Nic::Mac_address _mac_addr;
Nic::Rx_buffer_alloc &_alloc;
static void _link_callback() { instance->link_state_changed(); }
public:
Driver(Nic::Rx_buffer_alloc &alloc)
: _alloc(alloc)
Driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification &notify)
: _alloc(alloc), _notify(notify)
{
PINF("--- init iPXE NIC");
int cnt = dde_ipxe_nic_init();
PINF(" number of devices: %d", cnt);
PINF("--- init rx_callbacks");
dde_ipxe_nic_register_rx_callback(dde_rx_handler);
PINF("--- init callbacks");
dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
@ -70,16 +73,23 @@ namespace Ipxe {
Genode::memcpy(buffer, packet, packet_len);
_alloc.submit();
} catch (...) {
PDBG("failed to process received packet");
PDBG("failed to process received packet");
}
}
void link_state_changed() { _notify.link_state_changed(); }
/***************************
** Nic::Driver interface **
***************************/
Nic::Mac_address mac_address() { return _mac_addr; }
Nic::Mac_address mac_address() override { return _mac_addr; }
bool link_state() override
{
return dde_ipxe_nic_link_state(1);
}
void tx(char const *packet, Genode::size_t size)
{
@ -87,7 +97,6 @@ namespace Ipxe {
PWRN("Sending packet failed!");
}
/******************************
** Irq_activation interface **
******************************/
@ -97,9 +106,10 @@ namespace Ipxe {
class Driver_factory : public Nic::Driver_factory
{
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc)
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
Nic::Driver_notification &notify)
{
Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc);
Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc, notify);
return Driver::instance;
}

View File

@ -36,32 +36,35 @@ namespace Ipxe {
static Driver *instance;
static void dde_rx_handler(unsigned if_index,
const char *packet,
unsigned packet_len)
private:
Nic::Mac_address _mac_addr;
Nic::Rx_buffer_alloc &_alloc;
Nic::Driver_notification &_notify;
Timer::Connection _timer;
Nic::Measurement _stat;
static void _rx_callback(unsigned if_index,
const char *packet,
unsigned packet_len)
{
instance->rx_handler_stat(packet, packet_len);
}
private:
Nic::Mac_address _mac_addr;
Nic::Rx_buffer_alloc &_alloc;
Timer::Connection _timer;
Nic::Measurement _stat;
static void _link_callback() { instance->link_state_changed(); }
public:
Driver(Nic::Rx_buffer_alloc &alloc)
: _alloc(alloc), _stat(_timer)
Driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification &notify)
: _alloc(alloc), _notify(notify), _stat(_timer)
{
PINF("--- init iPXE NIC");
int cnt = dde_ipxe_nic_init();
PINF(" number of devices: %d", cnt);
PINF("--- init rx_callbacks");
dde_ipxe_nic_register_rx_callback(dde_rx_handler);
PINF("--- init callbacks");
dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
@ -90,6 +93,8 @@ namespace Ipxe {
_alloc.submit();
}
void link_state_changed() { _notify.link_state_changed(); }
/***************************
** Nic::Driver interface **
@ -97,6 +102,11 @@ namespace Ipxe {
Nic::Mac_address mac_address() { return _mac_addr; }
bool link_state() override
{
return dde_ipxe_nic_link_state(1);
}
void tx(char const *packet, Genode::size_t size)
{
if (dde_ipxe_nic_tx(1, packet, size))
@ -112,9 +122,9 @@ namespace Ipxe {
class Driver_factory : public Nic::Driver_factory
{
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc)
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification &notify)
{
Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc);
Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(alloc, notify);
return Driver::instance;
}

View File

@ -48,9 +48,15 @@ static struct dde_kit_sem *bh_sema;
static struct net_device *net_dev;
/**
* RX callback function pointer
* Link-state change detected
*/
static dde_ipxe_nic_rx_cb rx_callback;
static int link_state_changed;
/**
* Callback function pointers
*/
static dde_ipxe_nic_link_cb link_callback;
static dde_ipxe_nic_rx_cb rx_callback;
/**
* Known iPXE driver structures (located in the driver binaries)
@ -71,7 +77,6 @@ static struct pci_driver *pci_drivers[] = {
&pcnet32_driver
};
/**
* Update BARs of PCI device
*/
@ -201,9 +206,15 @@ static void irq_handler(void *p)
{
ENTER;
/* check for the link-state to change on each interrupt */
int link_ok = netdev_link_ok(net_dev);
/* poll the device for packets and also link-state changes */
netdev_poll(net_dev);
dde_kit_sem_up(bh_sema);
link_state_changed = (link_ok != netdev_link_ok(net_dev));
LEAVE;
}
@ -220,6 +231,15 @@ static void bh_handler(void *p)
ENTER;
/* report link-state changes */
if (link_state_changed) {
LEAVE;
if (link_callback)
link_callback();
ENTER;
link_state_changed = 0;
}
struct io_buffer *iobuf;
while ((iobuf = netdev_rx_dequeue(net_dev))) {
LEAVE;
@ -238,15 +258,30 @@ static void bh_handler(void *p)
** API implementation **
************************/
dde_ipxe_nic_rx_cb dde_ipxe_nic_register_rx_callback(dde_ipxe_nic_rx_cb cb)
void dde_ipxe_nic_register_callbacks(dde_ipxe_nic_rx_cb rx_cb,
dde_ipxe_nic_link_cb link_cb)
{
ENTER;
dde_ipxe_nic_rx_cb old = rx_callback;
rx_callback = cb;
rx_callback = rx_cb;
link_callback = link_cb;
LEAVE;
return old;
}
int dde_ipxe_nic_link_state(unsigned if_index)
{
if (if_index != 1)
return -1;
ENTER;
int link_state = netdev_link_ok(net_dev);
LEAVE;
return link_state;
}