71bd9a1f10
The nic_dump uses a wrapper for all supported protocols that takes a packet and a verbosity configuration. The wrapper object can than be used as argument for a Genode log function and prints the packet's contents according to the given configuration. The configuration is a distinct class to enable the reuse of one instance for different packets. There are currently 4 possible configurations for each protocol: * NONE (no output for this protocol) * SHORT (only the protocol name) * COMPACT (the most important information densely packed) * COMPREHENSIVE (all header information of this protocol) Ref #2490
110 lines
3.0 KiB
C++
110 lines
3.0 KiB
C++
/*
|
|
* \brief A net interface in form of a signal-driven NIC-packet handler
|
|
* \author Martin Stein
|
|
* \date 2017-03-08
|
|
*/
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
/* local includes */
|
|
#include <interface.h>
|
|
|
|
/* Genode includes */
|
|
#include <net/ethernet.h>
|
|
#include <packet_log.h>
|
|
|
|
using namespace Net;
|
|
using namespace Genode;
|
|
|
|
|
|
void Interface::_handle_eth(void *const eth_base,
|
|
size_t const eth_size,
|
|
Packet_descriptor const &pkt)
|
|
{
|
|
try {
|
|
Ethernet_frame ð = *new (eth_base) Ethernet_frame(eth_size);
|
|
Interface &remote = _remote.deref();
|
|
Packet_log_config log_cfg;
|
|
|
|
if (_log_time) {
|
|
Genode::Duration const new_time = _timer.curr_time();
|
|
unsigned long const new_time_ms = new_time.trunc_to_plain_us().value / 1000;
|
|
unsigned long const old_time_ms = _curr_time.trunc_to_plain_us().value / 1000;
|
|
|
|
log("\033[33m(", remote._label, " <- ", _label, ")\033[0m ",
|
|
packet_log(eth, log_cfg), " \033[33mtime ", new_time_ms,
|
|
" ms (Δ ", new_time_ms - old_time_ms, " ms)\033[0m");
|
|
|
|
_curr_time = new_time;
|
|
} else {
|
|
log("\033[33m(", remote._label, " <- ", _label, ")\033[0m ", packet_log(eth, log_cfg));
|
|
}
|
|
remote._send(eth, eth_size);
|
|
}
|
|
catch (Ethernet_frame::No_ethernet_frame) {
|
|
error("invalid ethernet frame"); }
|
|
|
|
catch (Pointer<Interface>::Invalid) {
|
|
error("no remote interface set"); }
|
|
}
|
|
|
|
|
|
void Interface::_send(Ethernet_frame ð, Genode::size_t const size)
|
|
{
|
|
try {
|
|
Packet_descriptor const pkt = _source().alloc_packet(size);
|
|
char *content = _source().packet_content(pkt);
|
|
Genode::memcpy((void *)content, (void *)ð, size);
|
|
_source().submit_packet(pkt);
|
|
}
|
|
catch (Packet_stream_source::Packet_alloc_failed) {
|
|
error("Failed to allocate packet"); }
|
|
}
|
|
|
|
|
|
void Interface::_ready_to_submit()
|
|
{
|
|
while (_sink().packet_avail()) {
|
|
|
|
Packet_descriptor const pkt = _sink().get_packet();
|
|
if (!pkt.size()) {
|
|
continue; }
|
|
|
|
_handle_eth(_sink().packet_content(pkt), pkt.size(), pkt);
|
|
|
|
if (!_sink().ready_to_ack()) {
|
|
error("ack state FULL");
|
|
return;
|
|
}
|
|
_sink().acknowledge_packet(pkt);
|
|
}
|
|
}
|
|
|
|
|
|
void Interface::_ready_to_ack()
|
|
{
|
|
while (_source().ack_avail()) {
|
|
_source().release_packet(_source().get_acked_packet()); }
|
|
}
|
|
|
|
|
|
Interface::Interface(Entrypoint &ep,
|
|
Interface_label label,
|
|
Timer::Connection &timer,
|
|
Duration &curr_time,
|
|
bool log_time,
|
|
Allocator &alloc)
|
|
:
|
|
_sink_ack (ep, *this, &Interface::_ack_avail),
|
|
_sink_submit (ep, *this, &Interface::_ready_to_submit),
|
|
_source_ack (ep, *this, &Interface::_ready_to_ack),
|
|
_source_submit(ep, *this, &Interface::_packet_avail),
|
|
_alloc(alloc), _label(label), _timer(timer), _curr_time(curr_time),
|
|
_log_time(log_time)
|
|
{ }
|