nic_dump: configurable packet print

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
This commit is contained in:
Martin Stein 2017-09-17 23:10:39 +02:00 committed by Christian Helmuth
parent d63c40af3e
commit 71bd9a1f10
4 changed files with 417 additions and 5 deletions

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <net/ethernet.h>
#include <packet_log.h>
using namespace Net;
using namespace Genode;
@ -28,18 +29,20 @@ void Interface::_handle_eth(void *const eth_base,
try {
Ethernet_frame &eth = *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 ", eth,
" \033[33mtime ", new_time_ms, " ms (Δ ",
new_time_ms - old_time_ms, " ms)\033[0m");
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 ", eth);
log("\033[33m(", remote._label, " <- ", _label, ")\033[0m ", packet_log(eth, log_cfg));
}
remote._send(eth, eth_size);
}

View File

@ -0,0 +1,290 @@
/*
* \brief Configurable print functionality for network packets
* \author Martin Stein
* \date 2017-09-27
*/
/*
* Copyright (C) 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 <packet_log.h>
using namespace Genode;
using namespace Net;
template <>
void Packet_log<Dhcp_packet>::print(Output &output) const
{
using Genode::print;
/* print header attributes */
switch (_cfg.dhcp) {
case Packet_log_style::COMPREHENSIVE:
print(output, "\033[32mDHCP\033[0m");
print(output, " op ", _pkt.op());
print(output, " htyp ", (uint8_t)_pkt.htype());
print(output, " hlen ", _pkt.hlen());
print(output, " hps ", _pkt.hops());
print(output, " xid ", _pkt.xid());
print(output, " sec ", _pkt.secs());
print(output, " flg ", Hex(_pkt.flags()));
print(output, " ci ", _pkt.ciaddr());
print(output, " yi ", _pkt.yiaddr());
print(output, " si ", _pkt.siaddr());
print(output, " gi ", _pkt.giaddr());
print(output, " ch ", _pkt.client_mac());
print(output, " srv ", _pkt.server_name());
print(output, " file ", _pkt.file());
print(output, " mag ", _pkt.magic_cookie());
print(output, " opt");
_pkt.for_each_option([&] (Dhcp_packet::Option &opt) {
print(output, " ", opt);
});
break;
case Packet_log_style::COMPACT:
print(output, _pkt);
break;
case Packet_log_style::SHORT:
print(output, "\033[32mDHCP\033[0m");
break;
default: ;
}
}
void Dhcp_packet::Option::print(Output &output) const
{
using Genode::print;
print(output, _code, ":", _len);
if (!len()) {
return;
}
print(output, ":");
for (unsigned j = 0; j < len(); j++) {
print(output, Hex(_value[j], Hex::OMIT_PREFIX, Hex::PAD));
}
}
template <>
void Packet_log<Arp_packet>::print(Output &output) const
{
using Genode::print;
/* print header attributes */
switch (_cfg.arp) {
case Packet_log_style::COMPREHENSIVE:
print(output, "\033[32mARP\033[0m");
print(output, " hw ", _pkt.hardware_address_type());
print(output, " prot ", _pkt.protocol_address_type());
print(output, " hwsz ", _pkt.hardware_address_size());
print(output, " protsz ", _pkt.protocol_address_size());
print(output, " op ", _pkt.opcode());
if (_pkt.ethernet_ipv4()) {
print(output, " srcmac ", _pkt.src_mac());
print(output, " srcip ", _pkt.src_ip());
print(output, " dstmac ", _pkt.dst_mac());
print(output, " dstip ", _pkt.dst_ip());
} else {
print(output, " ...");
}
break;
case Packet_log_style::COMPACT:
print(output, _pkt);
break;
case Packet_log_style::SHORT:
print(output, "\033[32mARP\033[0m");
break;
default: ;
}
}
template <>
void Packet_log<Ethernet_frame>::print(Output &output) const
{
using Genode::print;
/* print header attributes */
switch (_cfg.eth) {
case Packet_log_style::COMPREHENSIVE:
print(output, "\033[32mETH\033[0m");
print(output, " src ", _pkt.src());
print(output, " dst ", _pkt.dst());
print(output, " typ ", (Genode::uint16_t)_pkt.type());
break;
case Packet_log_style::COMPACT:
print(output, _pkt);
break;
case Packet_log_style::SHORT:
print(output, "\033[32mETH\033[0m");
break;
default: ;
}
/* print encapsulated packet */
switch (_pkt.type()) {
case Ethernet_frame::Type::ARP:
print(output, " ", packet_log(*_pkt.data<Arp_packet const>(), _cfg));
break;
case Ethernet_frame::Type::IPV4:
print(output, " ", packet_log(*_pkt.data<Ipv4_packet const>(), _cfg));
break;
default: ;
}
}
template <>
void Packet_log<Ipv4_packet>::print(Output &output) const
{
using Genode::print;
/* print header attributes */
switch (_cfg.ipv4) {
case Packet_log_style::COMPREHENSIVE:
print(output, "\033[32mIPV4\033[0m");
print(output, " hdrlen ", _pkt.header_length());
print(output, " ver ", _pkt.version());
print(output, " dsrv ", _pkt.diff_service());
print(output, " ecn ", _pkt.ecn());
print(output, " len ", _pkt.total_length());
print(output, " id ", _pkt.identification());
print(output, " flg ", _pkt.flags());
print(output, " frgoff ", _pkt.fragment_offset());
print(output, " ttl ", _pkt.time_to_live());
print(output, " prot ", (uint8_t)_pkt.protocol());
print(output, " crc ", _pkt.checksum());
print(output, " src ", _pkt.src());
print(output, " dst ", _pkt.dst());
break;
case Packet_log_style::COMPACT:
print(output, _pkt);
break;
case Packet_log_style::SHORT:
print(output, "\033[32mIPV4\033[0m");
break;
default: ;
}
/* print encapsulated packet */
switch (_pkt.protocol()) {
case Ipv4_packet::Protocol::TCP:
print(output, " ", packet_log(*_pkt.data<Tcp_packet const>(), _cfg));
break;
case Ipv4_packet::Protocol::UDP:
print(output, " ", packet_log(*_pkt.data<Udp_packet const>(), _cfg));
break;
default: ; }
}
template <>
void Packet_log<Tcp_packet>::print(Output &output) const
{
using Genode::print;
/* print header attributes */
switch (_cfg.tcp) {
case Packet_log_style::COMPREHENSIVE:
print(output, "\033[32mTCP\033[0m");
print(output, " src ", _pkt.src_port());
print(output, " dst ", _pkt.dst_port());
print(output, " seqn ", _pkt.seq_nr());
print(output, " ackn ", _pkt.ack_nr());
print(output, " doff ", _pkt.data_offset());
print(output, " flg ", _pkt.flags());
print(output, " winsz ", _pkt.window_size());
print(output, " crc ", _pkt.checksum());
print(output, " urgp ", _pkt.urgent_ptr());
break;
case Packet_log_style::COMPACT:
print(output, _pkt);
break;
case Packet_log_style::SHORT:
print(output, "\033[32mTCP\033[0m");
break;
default: ;
}
}
template <>
void Packet_log<Udp_packet>::print(Output &output) const
{
using Genode::print;
/* print header attributes */
switch (_cfg.udp) {
case Packet_log_style::COMPREHENSIVE:
print(output, "\033[32mUDP\033[0m");
print(output, " src ", _pkt.src_port());
print(output, " dst ", _pkt.dst_port());
print(output, " len ", _pkt.length());
print(output, " crc ", _pkt.checksum());
break;
case Packet_log_style::COMPACT:
print(output, _pkt);
break;
case Packet_log_style::SHORT:
print(output, "\033[32mUDP\033[0m");
break;
default: ;
}
/* print encapsulated packet */
if (Dhcp_packet::is_dhcp(&_pkt)) {
print(output, " ", packet_log(*_pkt.data<Dhcp_packet const>(), _cfg));
}
}

View File

@ -0,0 +1,119 @@
/*
* \brief Configurable print functionality for network packets
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2017-09-27
*/
/*
* Copyright (C) 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 _PACKET_LOG_H_
#define _PACKET_LOG_H_
/* Genode includes */
#include <base/stdint.h>
#include <net/arp.h>
#include <net/udp.h>
#include <net/dhcp.h>
#include <net/ethernet.h>
#include <net/tcp.h>
#include <net/ipv4.h>
namespace Net {
enum class Packet_log_style : Genode::uint8_t
{
NONE, SHORT, COMPACT, COMPREHENSIVE,
};
struct Packet_log_config;
template <typename PKT>
struct Packet_log;
}
/**
* Configuration for the print functionality of network packets
*/
struct Net::Packet_log_config
{
using Style = Packet_log_style;
Style eth, arp, ipv4, dhcp, udp, tcp;
Packet_log_config(Style def = Style::COMPACT)
: eth(def), arp(def), ipv4(def), dhcp(def), udp(def), tcp(def) { }
Packet_log_config(Style eth,
Style arp,
Style ipv4,
Style dhcp,
Style udp,
Style tcp)
: eth(eth), arp(arp), ipv4(ipv4), dhcp(dhcp), udp(udp), tcp(tcp) { }
};
/**
* Wrapper for network packets to configure their print functionality
*/
template <typename PKT>
class Net::Packet_log
{
private:
PKT const &_pkt;
Packet_log_config const &_cfg;
public:
Packet_log(PKT const &pkt, Packet_log_config const &cfg)
: _pkt(pkt), _cfg(cfg) { }
/*********
** log **
*********/
void print(Genode::Output &output) const;
};
namespace Net {
/* getting an instances via a function enables template-arg deduction */
template <typename PKT>
Packet_log<PKT> packet_log(PKT const &pkt, Packet_log_config const &cfg) {
return Packet_log<PKT>(pkt, cfg); }
/************************************************************
** Packet log specializations for all supported protocols **
************************************************************/
template <>
void Packet_log<Arp_packet>::print(Genode::Output &output) const;
template <>
void Packet_log<Ethernet_frame>::print(Genode::Output &output) const;
template <>
void Packet_log<Dhcp_packet>::print(Genode::Output &output) const;
template <>
void Packet_log<Ipv4_packet>::print(Genode::Output &output) const;
template <>
void Packet_log<Tcp_packet>::print(Genode::Output &output) const;
template <>
void Packet_log<Udp_packet>::print(Genode::Output &output) const;
}
#endif /* _PACKET_LOG_H_ */

View File

@ -2,6 +2,6 @@ TARGET = nic_dump
LIBS += base net
SRC_CC += component.cc main.cc uplink.cc interface.cc
SRC_CC += component.cc main.cc packet_log.cc uplink.cc interface.cc
INC_DIR += $(PRG_DIR)