Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Ability to dump packets to shared memory on "dump" rule in pcap format #259

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "subprojects/json"]
path = subprojects/json
url = https://github.com/nlohmann/json.git
[submodule "subprojects/pcap"]
path = subprojects/pcap
url = https://github.com/seladb/PcapPlusPlus.git
155 changes: 79 additions & 76 deletions autotest/autotest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@

#include <gmock/gmock.h>

#include "PcapFileDevice.h"
#include "autotest.h"
#include "common.h"

#include "common/define.h"
#include "common/sdpclient.h"
#include "common/sdpcommon.h"
#include "common/utils.h"

#define MAX_PACK_LEN 16384
Expand Down Expand Up @@ -175,7 +178,7 @@ eResult tAutotest::initSharedMemory()

void* shm = shm_by_key[ipcKey];
auto memaddr = (void*)((intptr_t)shm + offset);
dumpRings[name] = common::bufferring(memaddr, unitSize, unitsNumber);
dumpRings[name] = common::PacketBufferRing(memaddr, unitSize, unitsNumber);
}

return eResult::success;
Expand Down Expand Up @@ -235,8 +238,7 @@ void tAutotest::sendThread(std::string interfaceName,
pcap_errbuf);
if (!pcap)
{
YANET_LOG_ERROR("error: pcap_open_offline(): %s\n", pcap_errbuf);
throw "";
YANET_THROW("error: pcap_open_offline(): ", pcap_errbuf);
}

pcap_pkthdr* header = nullptr;
Expand Down Expand Up @@ -270,8 +272,7 @@ void tAutotest::sendThread(std::string interfaceName,

if (writeIovCount(iface, iov, iov_count) < 0)
{
YANET_LOG_ERROR("error: write packet(): %s\n", strerror(errno));
throw "";
YANET_THROW("error: write packet(): ", strerror(errno));
}

packetsCount++;
Expand Down Expand Up @@ -326,8 +327,7 @@ static bool readPacket(int fd, pcap_pkthdr* header, u_char* data, Duration timel

if (hdr.data_length == 0)
{
YANET_LOG_ERROR("error: read size is 0\n");
throw "";
YANET_THROW("error: read size is 0");
}

if (!readTimeLimited(fd, data, hdr.data_length, time_to_give_up))
Expand Down Expand Up @@ -416,16 +416,14 @@ class PcapDumper

if (!pcap)
{
YANET_LOG_ERROR("error: pcap_open_dead()\n");
throw "";
YANET_THROW("error: pcap_open_dead()");
}

dumper = pcap_dump_open(pcap, tmpFilePath.data());
if (!dumper)
{
pcap_close(pcap);
YANET_LOG_ERROR("error: pcap_dump_open()\n");
throw "";
YANET_THROW("error: pcap_dump_open()");
}
}

Expand Down Expand Up @@ -484,8 +482,7 @@ class pcap_expectation
pcap = pcap_open_offline(filename.c_str(), pcap_errbuf);
if (!pcap)
{
YANET_LOG_ERROR("error: pcap_open_offline(): %s\n", pcap_errbuf);
throw "";
YANET_THROW("error: pcap_open_offline(): ", pcap_errbuf);
}
memset(&header, 0, sizeof(struct pcap_pkthdr));
advance();
Expand Down Expand Up @@ -609,8 +606,7 @@ void tAutotest::recvThread(std::string interfaceName,
auto now = std::chrono::system_clock::now();
if (now > time_to_give_up)
{
YANET_LOG_ERROR("error[%s]: step time limit exceeded\n", interfaceName.data());
throw "";
YANET_THROW("error[", interfaceName, "]: step time limit exceeded");
}
if (!readPacket(iface, &tmp_pcap_packetHeader, buffer, time_to_give_up - now))
{
Expand All @@ -633,11 +629,7 @@ void tAutotest::recvThread(std::string interfaceName,
packetsCount + 1,
buf.str().data());

YANET_LOG_ERROR("pcap[%s]: %s\n",
interfaceName.data(),
pcapDumper.path().data());

throw "";
YANET_LOG_ERROR("pcap[%s]: %s\n", interfaceName.data(), pcapDumper.path().data());
}

if (dumpPackets)
Expand Down Expand Up @@ -735,8 +727,6 @@ void tAutotest::recvThread(std::string interfaceName,
YANET_LOG_ERROR("pcap[%s]: %s\n",
interfaceName.data(),
pcapDumper.path().data());

throw "";
}

unlink(pcapDumper.path().data());
Expand Down Expand Up @@ -960,7 +950,7 @@ bool tAutotest::step_sendPackets(const YAML::Node& yamlStep,

if (!success)
{
throw "";
YANET_THROW("");
}

return true;
Expand Down Expand Up @@ -1327,8 +1317,7 @@ void tAutotest::mainThread()
const auto result = controlPlane.loadConfig(request);
if (result != eResult::success)
{
YANET_LOG_ERROR("invalid config: eResult %d\n", static_cast<std::uint32_t>(result));
throw "";
YANET_THROW("invalid config: eResult ", common::result_to_c_str(result));
}
controlPlane.rib_flush();

Expand Down Expand Up @@ -1483,13 +1472,12 @@ void tAutotest::mainThread()
}
else
{
YANET_LOG_ERROR("unknown step\n");
throw "";
YANET_THROW("unknown step");
}

if (!result)
{
throw "";
YANET_THROW("");
}
}
}
Expand Down Expand Up @@ -1894,14 +1882,16 @@ bool tAutotest::step_cli_check(const YAML::Node& yamlStep)
return true;
}

common::bufferring::item_t* read_shm_packet(common::bufferring* buffer, uint64_t position)
common::PacketBufferRing::item_t* read_shm_packet(common::PacketBufferRing* buffer, uint64_t position)
{
if (position >= buffer->ring->header.after)
common::PacketBufferRing::ring_t* ring = buffer->ring;

if (position >= ring->header.after)
{
return nullptr;
}
auto* item = (common::bufferring::item_t*)((uintptr_t)buffer->ring->memory + (position * buffer->unit_size));
return item;

return utils::ShiftBuffer<common::PacketBufferRing::item_t*>(ring->memory, position * buffer->unit_size);
}

bool tAutotest::step_dumpPackets(const YAML::Node& yamlStep,
Expand All @@ -1914,86 +1904,99 @@ bool tAutotest::step_dumpPackets(const YAML::Node& yamlStep,
std::string expectFilePath = path + "/" + yamlDump["expect"].as<std::string>();
bool success = true;

common::bufferring* ring = nullptr;
common::PacketBufferRing* ring = nullptr;
{ /// searching memory ring by tag
auto it = dumpRings.find(tag);
if (it == dumpRings.end())
{
YANET_LOG_ERROR("dump [%s]: error: dump ring not found\n", tag.data());
throw "";
YANET_THROW("dump [", tag, "]: error: dump ring not found");
}
ring = &it->second;
}

pcap_t* pcap = nullptr;
{ /// open pcap file with expected data
char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap = pcap_open_offline(expectFilePath.data(), pcap_errbuf);
if (!pcap)
{
YANET_LOG_ERROR("dump [%s]: error: pcap_open_offline(): %s\n", tag.data(), pcap_errbuf);
throw "";
}
// Open pcap file using PcapPlusPlus
pcpp::IFileReaderDevice* reader = pcpp::IFileReaderDevice::getReader(expectFilePath);
if (reader == nullptr)
{
YANET_THROW("dump [", tag, "]: error: cannot determine reader for file ", expectFilePath);
}

struct pcap_pkthdr header;
const u_char* pcap_packet = nullptr;
common::bufferring::item_t* shm_packet = nullptr;
if (!reader->open())
{
YANET_THROW("dump [", tag, "]: error: cannot open pcap file", expectFilePath);
}

pcpp::RawPacket rawPacket;
common::PacketBufferRing::item_t* shm_packet;
uint64_t position = 0;

/// read packets from pcap and compare them with packets from memory ring
while ((pcap_packet = pcap_next(pcap, &header)))
while (reader->getNextPacket(rawPacket))
{
shm_packet = read_shm_packet(ring, position);
position++;

if (shm_packet && header.len == shm_packet->header.size &&
memcmp(shm_packet->memory, pcap_packet, header.len) == 0)
{ /// packets are the same
continue;
if (!shm_packet)
{
success = false;
YANET_LOG_ERROR("dump [%s]: error: missing packet #%lu in shared memory\n", tag.data(), position);
break;
}

/// packets are different, so...
success = false;
YANET_LOG_ERROR("dump [%s]: error: wrong packet #%lu (%s)\n",
tag.data(),
position,
expectFilePath.data());

if (dumpPackets && shm_packet)
// Compare the packet data
if (static_cast<size_t>(rawPacket.getRawDataLen()) == shm_packet->header.size &&
memcmp(rawPacket.getRawData(), shm_packet->memory, rawPacket.getRawDataLen()) == 0)
{
YANET_LOG_DEBUG("dump [%s]: expected %u, got %u\n", tag.data(), header.len, shm_packet->header.size);
dumper.dump(pcap_packet, pcap_packet + shm_packet->header.size, shm_packet->memory, shm_packet->memory + header.len);
/// packets are the same
continue;
}
}

/// read the remaining packets from memory ring
for (;;)
{
shm_packet = read_shm_packet(ring, position);
if (!shm_packet)
else
{
/// packets are different
success = false;
YANET_LOG_ERROR("dump [%s]: error: packet #%lu does not match (%s)\n",
tag.data(),
position,
expectFilePath.data());

if (dumpPackets)
{
YANET_LOG_DEBUG("dump [%s]: expected %u bytes, got %u bytes\n",
tag.data(),
rawPacket.getRawDataLen(),
shm_packet->header.size);
dumper.dump(rawPacket.getRawData(),
rawPacket.getRawData() + rawPacket.getRawDataLen(),
shm_packet->memory,
shm_packet->memory + shm_packet->header.size);
}
break;
}
position++;
}

/// Check for extra packets in shared memory
shm_packet = read_shm_packet(ring, position);
if (shm_packet)
{
success = false;
YANET_LOG_ERROR("dump [%s]: error: extra packet #%lu in shared memory\n", tag.data(), position + 1);

if (dumpPackets)
{
YANET_LOG_DEBUG("dump [%s]: unexpected %u\n", tag.data(), shm_packet->header.size);
dumper.dump(nullptr, nullptr, shm_packet->memory, shm_packet->memory + header.len);
YANET_LOG_DEBUG("dump [%s]: unexpected packet size %u bytes\n",
tag.data(),
shm_packet->header.size);
dumper.dump(nullptr, nullptr, shm_packet->memory, shm_packet->memory + shm_packet->header.size);
}
}

YANET_LOG_DEBUG("dump [%s]: recv %lu packets\n", tag.data(), position);
YANET_LOG_DEBUG("dump [%s]: compared %lu packets\n", tag.data(), position);

pcap_close(pcap);
reader->close();

if (!success)
{
YANET_LOG_ERROR("dump [%s]: error: unknown packet (%s)\n", tag.data(), expectFilePath.data());
throw "";
YANET_THROW("dump [", tag, "]: error: packet comparison failed", expectFilePath);
}
}

Expand Down
3 changes: 2 additions & 1 deletion autotest/autotest.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ class tAutotest
pcaps;

std::tuple<size_t, void*> rawShmInfo;
std::map<std::string, common::bufferring> dumpRings;
// TODO: this should be DumpRingBase instead of PacketBufferRing.
std::map<std::string, common::PacketBufferRing> dumpRings;

std::vector<std::thread> threads;
volatile bool flagStop;
Expand Down
3 changes: 3 additions & 0 deletions autotest/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ sources = files('autotest.cpp',
'main.cpp')

dependencies = []
dependencies += libdpdk.get_variable('dpdk_dep')
dependencies += libjson.get_variable('nlohmann_json_dep')
dependencies += dependency('libsystemd')
dependencies += dependency('yaml-cpp', static: true)
dependencies += dependency('libpcap', static: true)
dependencies += dependency('gmock')
dependencies += pcapplusplus_deps

executable('yanet-autotest',
sources,
include_directories: yanet_rootdir,
dependencies: dependencies,
link_args : ['-lstdc++fs'],
# override_options: 'b_lto=false',
install: true)

install_data('yanet-autotest-run.py', install_dir: get_option('bindir'))
1 change: 1 addition & 0 deletions cli/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ inline std::vector<bus_request_info> get_bus_requests(common::sdp::DataPlaneInSh
{common::idp::requestType::update_vip_vport_proto, "update_vip_vport_proto"},
{common::idp::requestType::version, "version"},
{common::idp::requestType::get_shm_info, "get_shm_info"},
{common::idp::requestType::hexdump_ring, "hexdump_ring"},
{common::idp::requestType::get_shm_tsc_info, "get_shm_tsc_info"},
{common::idp::requestType::set_shm_tsc_state, "set_shm_tsc_state"},
{common::idp::requestType::dump_physical_port, "dump_physical_port"},
Expand Down
2 changes: 2 additions & 0 deletions cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ std::vector<std::tuple<std::string,
{"tsc set state", "[true|false]", [](const auto& args) { Call(show::shm_tsc_set_state, args); }},
{"tsc set base", "[handle] [value]", [](const auto& args) { Call(show::shm_tsc_set_base_value, args); }},
{},
{"hexdump ring", "<tag>", [](const auto& args) { Call(show::hexdump_ring, args); }},
{},
{"samples show", "", [](const auto& args) { Call(show::samples, args); }},
{"samples dump", "", [](const auto& args) { Call(show::samples_dump, args); }},
{},
Expand Down
8 changes: 8 additions & 0 deletions cli/show.h
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,14 @@ inline void shm_info()
response);
}

inline void hexdump_ring(const std::string& ring)
{
interface::dataPlane dataplane;
const auto& response = dataplane.hexdump_ring(ring);
std::cout << "Hexdump for the dump ring " << ring << ":\n"
<< response.hexdumped_ring << std::endl;
}

void shm_tsc_info()
{
interface::dataPlane dataplane;
Expand Down
Loading
Loading