Skip to content

Commit

Permalink
Add parser for /proc/net/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
bigzachattack authored and dtrugman committed Sep 19, 2022
1 parent 2840bb0 commit 645b35b
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/pfs/net.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class net final
net& operator=(net&&) = delete;

public:
std::vector<net_device> get_dev() const;

std::vector<net_socket> get_icmp() const;
std::vector<net_socket> get_icmp6() const;
std::vector<net_socket> get_raw() const;
Expand All @@ -61,6 +63,7 @@ class net final
net(const std::string& procfs_root);

private:
std::vector<net_device> get_net_devices(const std::string& file) const;
std::vector<net_socket> get_net_sockets(const std::string& file) const;

static std::string build_net_root(const std::string& procfs_root);
Expand Down
1 change: 1 addition & 0 deletions include/pfs/parsers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ uptime parse_uptime_line(const std::string& line);
module parse_modules_line(const std::string& line);
mem_region parse_maps_line(const std::string& line);
mount parse_mountinfo_line(const std::string& line);
net_device parse_net_device_line(const std::string& line);
net_socket parse_net_socket_line(const std::string& line);
unix_socket parse_unix_socket_line(const std::string& line);
netlink_socket parse_netlink_socket_line(const std::string& line);
Expand Down
21 changes: 21 additions & 0 deletions include/pfs/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,27 @@ struct ip
ipv6 storage;
};

struct net_device
{
std::string name;
uint64_t rx_bytes;
uint64_t rx_packets;
uint64_t rx_errors;
uint64_t rx_drop;
uint64_t rx_fifo;
uint64_t rx_frame;
uint64_t rx_compressed;
uint64_t rx_multicast;
uint64_t tx_bytes;
uint64_t tx_packets;
uint64_t tx_errors;
uint64_t tx_drop;
uint64_t tx_fifo;
uint64_t tx_colls;
uint64_t tx_carrier;
uint64_t tx_compressed;
};

// Hint: See 'get_tcp4_sock @ tcp_ipv4.c'
struct net_socket
{
Expand Down
3 changes: 3 additions & 0 deletions sample/enum_net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ int enum_net(std::vector<std::string>&& args)
pfs::procfs pfs;
auto net = pfs.get_net();

auto dev = net.get_dev();
print(dev);

auto icmp = net.get_icmp();
print(icmp);

Expand Down
23 changes: 23 additions & 0 deletions sample/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,29 @@ inline std::ostream& operator<<(std::ostream& out,
return out;
}

inline std::ostream& operator<<(std::ostream& out,
const pfs::net_device& device)
{
out << "name[" << device.name << "] ";
out << "rx_bytes[" << device.rx_bytes << "] ";
out << "rx_packets[" << device.rx_packets << "] ";
out << "rx_errors[" << device.rx_errors << "] ";
out << "rx_drop[" << device.rx_drop << "] ";
out << "rx_fifo[" << device.rx_fifo << "] ";
out << "rx_frame[" << device.rx_frame << "] ";
out << "rx_compressed[" << device.rx_compressed << "] ";
out << "rx_multicast[" << device.rx_multicast << "] ";
out << "tx_bytes[" << device.tx_bytes << "] ";
out << "tx_packets[" << device.tx_packets << "] ";
out << "tx_errors[" << device.tx_errors << "] ";
out << "tx_drop[" << device.tx_drop << "] ";
out << "tx_fifo[" << device.tx_fifo << "] ";
out << "tx_colls[" << device.tx_colls << "] ";
out << "tx_carrier[" << device.tx_carrier << "] ";
out << "tx_compressed[" << device.tx_compressed << "] ";
return out;
}

inline std::ostream& operator<<(std::ostream& out,
const pfs::net_socket& socket)
{
Expand Down
16 changes: 16 additions & 0 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ std::string net::build_net_root(const std::string& procfs_root)
return procfs_root + NET_DIR;
}

std::vector<net_device> net::get_dev() const
{
static const std::string DEV_FILE("dev");
return get_net_devices(DEV_FILE);
}

std::vector<net_socket> net::get_icmp() const
{
static const std::string ICMP_FILE("icmp");
Expand Down Expand Up @@ -129,4 +135,14 @@ std::vector<net_socket> net::get_net_sockets(const std::string& file) const
return output;
}

std::vector<net_device> net::get_net_devices(const std::string& file) const
{
auto path = _net_root + file;

static const size_t HEADER_LINES = 2;
std::vector<net_device> output;
parsers::parse_lines(path, std::back_inserter(output), parsers::parse_net_device_line, HEADER_LINES);
return output;
}

} // namespace pfs
99 changes: 99 additions & 0 deletions src/parsers/net_device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2020-present Daniel Trugman
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "pfs/parsers.hpp"
#include "pfs/utils.hpp"

namespace pfs {
namespace impl {
namespace parsers {

net_device parse_net_device_line(const std::string& line)
{
// Example:
// clang-format off
// Inter-| Receive | Transmit
// face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
// lo: 27267010 48045 0 0 0 0 0 0 27267010 48045 0 0 0 0 0 0
// eth0: 335754274 58179 0 0 0 0 0 0 9805218 48519 0 0 0 0 0 0
// clang-format on

enum token {
NAME = 0,
RX_BYTES = 1,
RX_PACKETS = 2,
RX_ERRORS = 3,
RX_DROP = 4,
RX_FIFO = 5,
RX_FRAME = 6,
RX_COMPRESSED = 7,
RX_MULTICAST = 8,
TX_BYTES = 9,
TX_PACKETS = 10,
TX_ERRORS = 11,
TX_DROP = 12,
TX_FIFO = 13,
TX_COLLS = 14,
TX_CARRIER = 15,
TX_COMPRESSED = 16,
COUNT
};

auto tokens = utils::split(line);
if (tokens.size() != COUNT)
{
throw parser_error("Corrupted net device line - Wrong number of tokens",
line);
}

try {
net_device dev;

dev.name = tokens[NAME];
dev.name.pop_back(); // Remove ':';

utils::stot(tokens[RX_BYTES], dev.rx_bytes, utils::base::decimal);
utils::stot(tokens[RX_PACKETS], dev.rx_packets, utils::base::decimal);
utils::stot(tokens[RX_ERRORS], dev.rx_errors, utils::base::decimal);
utils::stot(tokens[RX_DROP], dev.rx_drop, utils::base::decimal);
utils::stot(tokens[RX_FIFO], dev.rx_fifo, utils::base::decimal);
utils::stot(tokens[RX_FRAME], dev.rx_frame, utils::base::decimal);
utils::stot(tokens[RX_COMPRESSED], dev.rx_compressed, utils::base::decimal);
utils::stot(tokens[RX_MULTICAST], dev.rx_multicast, utils::base::decimal);
utils::stot(tokens[TX_BYTES], dev.tx_bytes, utils::base::decimal);
utils::stot(tokens[TX_PACKETS], dev.tx_packets, utils::base::decimal);
utils::stot(tokens[TX_ERRORS], dev.tx_errors, utils::base::decimal);
utils::stot(tokens[TX_DROP], dev.tx_drop, utils::base::decimal);
utils::stot(tokens[TX_FIFO], dev.tx_fifo, utils::base::decimal);
utils::stot(tokens[TX_COLLS], dev.tx_colls, utils::base::decimal);
utils::stot(tokens[TX_CARRIER], dev.tx_carrier, utils::base::decimal);
utils::stot(tokens[TX_COMPRESSED], dev.tx_compressed, utils::base::decimal);

return dev;
}
catch (const std::invalid_argument& ex)
{
throw parser_error("Corrupted net device - Invalid argument", line);
}
catch (const std::out_of_range& ex)
{
throw parser_error("Corrupted net device - Out of range", line);
}
}

} // namespace parsers
} // namespace impl
} // namespace pfs
79 changes: 79 additions & 0 deletions test/net_device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include <sstream>

#include "catch.hpp"
#include "test_utils.hpp"

#include "pfs/parsers.hpp"

using namespace pfs::impl::parsers;

TEST_CASE("Parse corrupted net device", "[net][net_device]")
{

SECTION("Missing token")
{
std::string line =
"lo: 27267010 48045 0 0 0 0 0 0 "
"27267010 48045 0 0 0 0 0";

REQUIRE_THROWS_AS(parse_net_device_line(line), pfs::parser_error);
}

SECTION("Extra token")
{
std::string line =
"lo: 27267010 48045 0 0 0 0 0 0 "
"27267010 48045 0 0 0 0 0 0 0";

REQUIRE_THROWS_AS(parse_net_device_line(line), pfs::parser_error);
}

}

TEST_CASE("Parse net device", "[net][net_device]")
{

pfs::net_device expected;

std::string line =
"eth0: 335754274 58179 1 2 3 4 5 "
"6 9805218 48519 11 12 13 14 15 16";

expected.name = "eth0";
expected.rx_bytes = 335754274;
expected.rx_packets = 58179;
expected.rx_errors = 1;
expected.rx_drop = 2;
expected.rx_fifo = 3;
expected.rx_frame = 4;
expected.rx_compressed = 5;
expected.rx_multicast = 6;
expected.tx_bytes = 9805218;
expected.tx_packets = 48519;
expected.tx_errors = 11;
expected.tx_drop = 12;
expected.tx_fifo = 13;
expected.tx_colls = 14;
expected.tx_carrier = 15;
expected.tx_compressed = 16;

auto device = parse_net_device_line(line);

REQUIRE(device.name == expected.name);
REQUIRE(device.rx_bytes == expected.rx_bytes);
REQUIRE(device.rx_packets == expected.rx_packets);
REQUIRE(device.rx_errors == expected.rx_errors);
REQUIRE(device.rx_drop == expected.rx_drop);
REQUIRE(device.rx_fifo == expected.rx_fifo);
REQUIRE(device.rx_compressed == expected.rx_compressed);
REQUIRE(device.rx_multicast == expected.rx_multicast);
REQUIRE(device.tx_bytes == expected.tx_bytes);
REQUIRE(device.tx_packets == expected.tx_packets);
REQUIRE(device.tx_errors == expected.tx_errors);
REQUIRE(device.tx_drop == expected.tx_drop);
REQUIRE(device.tx_fifo == expected.tx_fifo);
REQUIRE(device.tx_colls == expected.tx_colls);
REQUIRE(device.tx_carrier == expected.tx_carrier);
REQUIRE(device.tx_compressed == expected.tx_compressed);

}

0 comments on commit 645b35b

Please sign in to comment.