mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 04:08:11 +00:00
Kernel: Record network statistics and expose as JSON
This is comprised of five small changes: * Keep a counter for tx/rx packets/bytes per TCP socket * Keep a counter for tx/rx packets/bytes per network adapter * Expose that data in /proc/net_tcp and /proc/netadapters * Convert /proc/netadapters to JSON * Fix up ifconfig to read the JSON from netadapters
This commit is contained in:
parent
061c092fae
commit
7ed54d86d5
7 changed files with 88 additions and 20 deletions
|
@ -269,15 +269,20 @@ Optional<KBuffer> procfs$cmdline(InodeIdentifier)
|
||||||
|
|
||||||
Optional<KBuffer> procfs$netadapters(InodeIdentifier)
|
Optional<KBuffer> procfs$netadapters(InodeIdentifier)
|
||||||
{
|
{
|
||||||
KBufferBuilder builder;
|
JsonArray json;
|
||||||
NetworkAdapter::for_each([&builder](auto& adapter) {
|
NetworkAdapter::for_each([&json](auto& adapter) {
|
||||||
builder.appendf("%s,%s,%s,%s\n",
|
JsonObject obj;
|
||||||
adapter.name().characters(),
|
obj.set("name", adapter.name());
|
||||||
adapter.class_name(),
|
obj.set("class_name", adapter.class_name());
|
||||||
adapter.mac_address().to_string().characters(),
|
obj.set("mac_address", adapter.mac_address().to_string());
|
||||||
adapter.ipv4_address().to_string().characters());
|
obj.set("ipv4_address", adapter.ipv4_address().to_string());
|
||||||
|
obj.set("packets_in", adapter.packets_in());
|
||||||
|
obj.set("bytes_in", adapter.bytes_in());
|
||||||
|
obj.set("packets_out", adapter.packets_out());
|
||||||
|
obj.set("bytes_out", adapter.bytes_out());
|
||||||
|
json.append(obj);
|
||||||
});
|
});
|
||||||
return builder.build();
|
return json.serialized<KBufferBuilder>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<KBuffer> procfs$net_tcp(InodeIdentifier)
|
Optional<KBuffer> procfs$net_tcp(InodeIdentifier)
|
||||||
|
@ -292,6 +297,10 @@ Optional<KBuffer> procfs$net_tcp(InodeIdentifier)
|
||||||
obj.set("state", TCPSocket::to_string(socket->state()));
|
obj.set("state", TCPSocket::to_string(socket->state()));
|
||||||
obj.set("ack_number", socket->ack_number());
|
obj.set("ack_number", socket->ack_number());
|
||||||
obj.set("sequence_number", socket->sequence_number());
|
obj.set("sequence_number", socket->sequence_number());
|
||||||
|
obj.set("packets_in", socket->packets_in());
|
||||||
|
obj.set("bytes_in", socket->bytes_in());
|
||||||
|
obj.set("packets_out", socket->packets_out());
|
||||||
|
obj.set("bytes_out", socket->bytes_out());
|
||||||
json.append(obj);
|
json.append(obj);
|
||||||
});
|
});
|
||||||
return json.serialized<KBufferBuilder>();
|
return json.serialized<KBufferBuilder>();
|
||||||
|
|
|
@ -52,6 +52,8 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
|
||||||
eth->set_source(mac_address());
|
eth->set_source(mac_address());
|
||||||
eth->set_destination(destination);
|
eth->set_destination(destination);
|
||||||
eth->set_ether_type(EtherType::ARP);
|
eth->set_ether_type(EtherType::ARP);
|
||||||
|
m_packets_out++;
|
||||||
|
m_bytes_out += size_in_bytes;
|
||||||
memcpy(eth->payload(), &packet, sizeof(ARPPacket));
|
memcpy(eth->payload(), &packet, sizeof(ARPPacket));
|
||||||
send_raw((u8*)eth, size_in_bytes);
|
send_raw((u8*)eth, size_in_bytes);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +76,8 @@ void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Addr
|
||||||
ipv4.set_ident(1);
|
ipv4.set_ident(1);
|
||||||
ipv4.set_ttl(64);
|
ipv4.set_ttl(64);
|
||||||
ipv4.set_checksum(ipv4.compute_checksum());
|
ipv4.set_checksum(ipv4.compute_checksum());
|
||||||
|
m_packets_out++;
|
||||||
|
m_bytes_out += size_in_bytes;
|
||||||
memcpy(ipv4.payload(), payload, payload_size);
|
memcpy(ipv4.payload(), payload, payload_size);
|
||||||
send_raw((const u8*)ð, size_in_bytes);
|
send_raw((const u8*)ð, size_in_bytes);
|
||||||
}
|
}
|
||||||
|
@ -81,6 +85,8 @@ void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Addr
|
||||||
void NetworkAdapter::did_receive(const u8* data, int length)
|
void NetworkAdapter::did_receive(const u8* data, int length)
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
|
m_packets_in++;
|
||||||
|
m_bytes_in += length;
|
||||||
m_packet_queue.append(KBuffer::copy(data, length));
|
m_packet_queue.append(KBuffer::copy(data, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,11 @@ public:
|
||||||
|
|
||||||
bool has_queued_packets() const { return !m_packet_queue.is_empty(); }
|
bool has_queued_packets() const { return !m_packet_queue.is_empty(); }
|
||||||
|
|
||||||
|
u32 packets_in() const { return m_packets_in; }
|
||||||
|
u32 bytes_in() const { return m_bytes_in; }
|
||||||
|
u32 packets_out() const { return m_packets_out; }
|
||||||
|
u32 bytes_out() const { return m_bytes_out; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NetworkAdapter();
|
NetworkAdapter();
|
||||||
void set_interface_name(const StringView& basename);
|
void set_interface_name(const StringView& basename);
|
||||||
|
@ -45,4 +50,8 @@ private:
|
||||||
IPv4Address m_ipv4_address;
|
IPv4Address m_ipv4_address;
|
||||||
SinglyLinkedList<KBuffer> m_packet_queue;
|
SinglyLinkedList<KBuffer> m_packet_queue;
|
||||||
String m_name;
|
String m_name;
|
||||||
|
u32 m_packets_in { 0 };
|
||||||
|
u32 m_bytes_in { 0 };
|
||||||
|
u32 m_packets_out { 0 };
|
||||||
|
u32 m_bytes_out { 0 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -334,6 +334,8 @@ void handle_tcp(const EthernetFrameHeader& eth, int frame_size)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket->record_incoming_data(ipv4_packet.payload_size());
|
||||||
|
|
||||||
#ifdef TCP_DEBUG
|
#ifdef TCP_DEBUG
|
||||||
kprintf("handle_tcp: state=%s\n", TCPSocket::to_string(socket->state()));
|
kprintf("handle_tcp: state=%s\n", TCPSocket::to_string(socket->state()));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -117,6 +117,15 @@ void TCPSocket::send_tcp_packet(u16 flags, const void* payload, int payload_size
|
||||||
tcp_packet.ack_number());
|
tcp_packet.ack_number());
|
||||||
#endif
|
#endif
|
||||||
m_adapter->send_ipv4(MACAddress(), peer_address(), IPv4Protocol::TCP, buffer.data(), buffer.size());
|
m_adapter->send_ipv4(MACAddress(), peer_address(), IPv4Protocol::TCP, buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
m_packets_out++;
|
||||||
|
m_bytes_out += buffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPSocket::record_incoming_data(int size)
|
||||||
|
{
|
||||||
|
m_packets_in++;
|
||||||
|
m_bytes_in += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket& packet, u16 payload_size)
|
NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket& packet, u16 payload_size)
|
||||||
|
|
|
@ -60,8 +60,13 @@ public:
|
||||||
void set_sequence_number(u32 n) { m_sequence_number = n; }
|
void set_sequence_number(u32 n) { m_sequence_number = n; }
|
||||||
u32 ack_number() const { return m_ack_number; }
|
u32 ack_number() const { return m_ack_number; }
|
||||||
u32 sequence_number() const { return m_sequence_number; }
|
u32 sequence_number() const { return m_sequence_number; }
|
||||||
|
u32 packets_in() const { return m_packets_in; }
|
||||||
|
u32 bytes_in() const { return m_bytes_in; }
|
||||||
|
u32 packets_out() const { return m_packets_out; }
|
||||||
|
u32 bytes_out() const { return m_bytes_out; }
|
||||||
|
|
||||||
void send_tcp_packet(u16 flags, const void* = nullptr, int = 0);
|
void send_tcp_packet(u16 flags, const void* = nullptr, int = 0);
|
||||||
|
void record_incoming_data(int);
|
||||||
|
|
||||||
static Lockable<HashMap<IPv4SocketTuple, TCPSocket*>>& sockets_by_tuple();
|
static Lockable<HashMap<IPv4SocketTuple, TCPSocket*>>& sockets_by_tuple();
|
||||||
static TCPSocketHandle from_tuple(const IPv4SocketTuple& tuple);
|
static TCPSocketHandle from_tuple(const IPv4SocketTuple& tuple);
|
||||||
|
@ -85,6 +90,10 @@ private:
|
||||||
u32 m_sequence_number { 0 };
|
u32 m_sequence_number { 0 };
|
||||||
u32 m_ack_number { 0 };
|
u32 m_ack_number { 0 };
|
||||||
State m_state { State::Closed };
|
State m_state { State::Closed };
|
||||||
|
u32 m_packets_in { 0 };
|
||||||
|
u32 m_bytes_in { 0 };
|
||||||
|
u32 m_packets_out { 0 };
|
||||||
|
u32 m_bytes_out { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class TCPSocketHandle : public SocketHandle {
|
class TCPSocketHandle : public SocketHandle {
|
||||||
|
|
|
@ -1,6 +1,21 @@
|
||||||
|
#include <AK/AKString.h>
|
||||||
|
#include <AK/JsonArray.h>
|
||||||
|
#include <AK/JsonObject.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
#include <LibCore/CFile.h>
|
#include <LibCore/CFile.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
String si_bytes(unsigned bytes)
|
||||||
|
{
|
||||||
|
if (bytes >= GB)
|
||||||
|
return String::format("%fGiB", (double)bytes / (double)GB);
|
||||||
|
if (bytes >= MB)
|
||||||
|
return String::format("%fMiB", (double)bytes / (double)MB);
|
||||||
|
if (bytes >= KB)
|
||||||
|
return String::format("%fKiB", (double)bytes / (double)KB);
|
||||||
|
return String::format("%dB", bytes);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
UNUSED_PARAM(argc);
|
UNUSED_PARAM(argc);
|
||||||
|
@ -12,19 +27,28 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
auto file_contents = file.read_all();
|
||||||
auto line = file.read_line(1024);
|
auto json = JsonValue::from_string(file_contents).as_array();
|
||||||
if (line.is_null())
|
json.for_each([](auto& value) {
|
||||||
break;
|
auto if_object = value.as_object();
|
||||||
auto parts = String::copy(line, Chomp).split(',');
|
|
||||||
if (parts.size() < 4)
|
auto name = if_object.get("name").to_string();
|
||||||
continue;
|
auto class_name = if_object.get("class_name").to_string();
|
||||||
printf("%s:\n", parts[0].characters());
|
auto mac_address = if_object.get("mac_address").to_string();
|
||||||
printf(" mac: %s\n", parts[2].characters());
|
auto ipv4_address = if_object.get("ipv4_address").to_string();
|
||||||
printf(" ipv4: %s\n", parts[3].characters());
|
auto packets_in = if_object.get("packets_in").to_u32();
|
||||||
printf(" class: %s\n", parts[1].characters());
|
auto bytes_in = if_object.get("bytes_in").to_u32();
|
||||||
|
auto packets_out = if_object.get("packets_out").to_u32();
|
||||||
|
auto bytes_out = if_object.get("bytes_out").to_u32();
|
||||||
|
|
||||||
|
printf("%s:\n", name.characters());
|
||||||
|
printf(" mac: %s\n", mac_address.characters());
|
||||||
|
printf(" ipv4: %s\n", ipv4_address.characters());
|
||||||
|
printf(" class: %s\n", class_name.characters());
|
||||||
|
printf(" RX: %u packets %u bytes (%s)\n", packets_in, bytes_in, si_bytes(bytes_in).characters());
|
||||||
|
printf(" TX: %u packets %u bytes (%s)\n", packets_out, bytes_out, si_bytes(bytes_out).characters());
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
});
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue