mirror of
https://github.com/espressif/openthread.git
synced 2026-08-14 06:37:46 +00:00
[nexus] update packet capture to pcapng format (#12660)
This commit updates the Nexus test framework to use the pcapng format for packet capture instead of the legacy pcap format. The pcapng format provides several advantages over legacy pcap, most importantly the ability to support multiple interface captures within a single file. This change prepares the Nexus framework for more comprehensive border router testing, where capturing traffic from both the Thread (802.15.4) and infrastructure (Ethernet) interfaces simultaneously is required. Changes: - Implemented Section Header Block (SHB) and Interface Description Block (IDB) in Pcap::Open. - Updated Pcap::WriteFrame to use Enhanced Packet Block (EPB). - Added proper 32-bit alignment padding for EPB records as required by the pcapng specification. - Updated the test runner script to use the .pcapng extension.
This commit is contained in:
@@ -44,30 +44,51 @@ Pcap::~Pcap(void) { Close(); }
|
||||
void Pcap::Open(const char *aFilename)
|
||||
{
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct PcapHeader
|
||||
struct Shb
|
||||
{
|
||||
uint32_t mMagicNumber;
|
||||
uint32_t mBlockType;
|
||||
uint32_t mBlockTotalLength;
|
||||
uint32_t mByteOrderMagic;
|
||||
uint16_t mVersionMajor;
|
||||
uint16_t mVersionMinor;
|
||||
int32_t mThisZone;
|
||||
uint32_t mSigFigs;
|
||||
uint64_t mSectionLength;
|
||||
uint32_t mBlockTotalLength2;
|
||||
} OT_TOOL_PACKED_END shb;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct Idb
|
||||
{
|
||||
uint32_t mBlockType;
|
||||
uint32_t mBlockTotalLength;
|
||||
uint16_t mLinkType;
|
||||
uint16_t mReserved;
|
||||
uint32_t mSnapLen;
|
||||
uint32_t mNetwork;
|
||||
} OT_TOOL_PACKED_END header;
|
||||
uint32_t mBlockTotalLength2;
|
||||
} OT_TOOL_PACKED_END idb;
|
||||
|
||||
Close();
|
||||
|
||||
mFile = fopen(aFilename, "wb");
|
||||
VerifyOrExit(mFile != nullptr);
|
||||
|
||||
ClearAllBytes(header);
|
||||
header.mMagicNumber = LittleEndian::HostSwap(kPcapMagicNumber);
|
||||
header.mVersionMajor = LittleEndian::HostSwap(kPcapVersionMajor);
|
||||
header.mVersionMinor = LittleEndian::HostSwap(kPcapVersionMinor);
|
||||
header.mSnapLen = LittleEndian::HostSwap(kPcapSnapLen);
|
||||
header.mNetwork = LittleEndian::HostSwap(kPcapDlt154Tap);
|
||||
ClearAllBytes(shb);
|
||||
shb.mBlockType = LittleEndian::HostSwap(kPcapngShbType);
|
||||
shb.mBlockTotalLength = LittleEndian::HostSwap(static_cast<uint32_t>(sizeof(shb)));
|
||||
shb.mByteOrderMagic = LittleEndian::HostSwap(kPcapngByteOrderMagic);
|
||||
shb.mVersionMajor = LittleEndian::HostSwap(kPcapngVersionMajor);
|
||||
shb.mVersionMinor = LittleEndian::HostSwap(kPcapngVersionMinor);
|
||||
shb.mSectionLength = 0xffffffffffffffffULL;
|
||||
shb.mBlockTotalLength2 = shb.mBlockTotalLength;
|
||||
VerifyOrExit(fwrite(&shb, sizeof(shb), 1, mFile) == 1, Close());
|
||||
|
||||
ClearAllBytes(idb);
|
||||
idb.mBlockType = LittleEndian::HostSwap(kPcapngIdbType);
|
||||
idb.mBlockTotalLength = LittleEndian::HostSwap(static_cast<uint32_t>(sizeof(idb)));
|
||||
idb.mLinkType = LittleEndian::HostSwap(static_cast<uint16_t>(kPcapngLinkTypeIeee802154));
|
||||
idb.mSnapLen = LittleEndian::HostSwap(kPcapngSnapLen);
|
||||
idb.mBlockTotalLength2 = idb.mBlockTotalLength;
|
||||
VerifyOrExit(fwrite(&idb, sizeof(idb), 1, mFile) == 1, Close());
|
||||
|
||||
VerifyOrExit(fwrite(&header, sizeof(header), 1, mFile) == 1, Close());
|
||||
VerifyOrExit(fflush(mFile) == 0, Close());
|
||||
|
||||
exit:
|
||||
@@ -88,13 +109,16 @@ exit:
|
||||
void Pcap::WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs)
|
||||
{
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct PcapRecordHeader
|
||||
struct Epb
|
||||
{
|
||||
uint32_t mTsSec;
|
||||
uint32_t mTsUsec;
|
||||
uint32_t mInclLen;
|
||||
uint32_t mOrigLen;
|
||||
} OT_TOOL_PACKED_END recordHeader;
|
||||
uint32_t mBlockType;
|
||||
uint32_t mBlockTotalLength;
|
||||
uint32_t mInterfaceId;
|
||||
uint32_t mTimestampHigh;
|
||||
uint32_t mTimestampLow;
|
||||
uint32_t mCapturedLen;
|
||||
uint32_t mOriginalLen;
|
||||
} OT_TOOL_PACKED_END epb;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct TapHeader
|
||||
@@ -104,6 +128,10 @@ void Pcap::WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs)
|
||||
} OT_TOOL_PACKED_END tapHeader;
|
||||
|
||||
uint32_t tapLength;
|
||||
uint32_t packetLen;
|
||||
uint32_t paddedLen;
|
||||
uint32_t blockTotalLength;
|
||||
uint32_t padding = 0;
|
||||
|
||||
VerifyOrExit(mFile != nullptr);
|
||||
|
||||
@@ -112,12 +140,19 @@ void Pcap::WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs)
|
||||
// FCS TLV: Type(2), Length(2), Value(1), Padding(3) -> Total 8 bytes. Value length = 1.
|
||||
// Channel TLV: Type(2), Length(2), Channel(2), Page(1), Padding(1) -> Total 8 bytes. Value length = 3.
|
||||
|
||||
ClearAllBytes(recordHeader);
|
||||
recordHeader.mTsSec = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs / 1000000));
|
||||
recordHeader.mTsUsec = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs % 1000000));
|
||||
recordHeader.mInclLen = LittleEndian::HostSwap(static_cast<uint32_t>(tapLength + aFrame.mLength));
|
||||
recordHeader.mOrigLen = recordHeader.mInclLen;
|
||||
VerifyOrExit(fwrite(&recordHeader, sizeof(recordHeader), 1, mFile) == 1, Close());
|
||||
packetLen = tapLength + aFrame.mLength;
|
||||
paddedLen = (packetLen + 3) & ~3u;
|
||||
blockTotalLength = sizeof(epb) + paddedLen + sizeof(uint32_t);
|
||||
|
||||
ClearAllBytes(epb);
|
||||
epb.mBlockType = LittleEndian::HostSwap(kPcapngEpbType);
|
||||
epb.mBlockTotalLength = LittleEndian::HostSwap(blockTotalLength);
|
||||
epb.mInterfaceId = 0;
|
||||
epb.mTimestampHigh = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs >> 32));
|
||||
epb.mTimestampLow = LittleEndian::HostSwap(static_cast<uint32_t>(aTimeUs & 0xffffffff));
|
||||
epb.mCapturedLen = LittleEndian::HostSwap(packetLen);
|
||||
epb.mOriginalLen = LittleEndian::HostSwap(packetLen);
|
||||
VerifyOrExit(fwrite(&epb, sizeof(epb), 1, mFile) == 1, Close());
|
||||
|
||||
ClearAllBytes(tapHeader);
|
||||
tapHeader.mVersion = LittleEndian::HostSwap(static_cast<uint16_t>(kTapVersion));
|
||||
@@ -142,6 +177,14 @@ void Pcap::WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs)
|
||||
VerifyOrExit(fwrite(channelTlv, sizeof(channelTlv), 1, mFile) == 1, Close());
|
||||
|
||||
VerifyOrExit(fwrite(aFrame.mPsdu, aFrame.mLength, 1, mFile) == 1, Close());
|
||||
|
||||
if (paddedLen > packetLen)
|
||||
{
|
||||
VerifyOrExit(fwrite(&padding, paddedLen - packetLen, 1, mFile) == 1, Close());
|
||||
}
|
||||
|
||||
VerifyOrExit(fwrite(&epb.mBlockTotalLength, sizeof(epb.mBlockTotalLength), 1, mFile) == 1, Close());
|
||||
|
||||
VerifyOrExit(fflush(mFile) == 0, Close());
|
||||
|
||||
exit:
|
||||
|
||||
@@ -44,19 +44,19 @@ public:
|
||||
~Pcap(void);
|
||||
|
||||
/**
|
||||
* Opens a pcap file.
|
||||
* Opens a pcapng file.
|
||||
*
|
||||
* @param[in] aFilename The filename to open.
|
||||
*/
|
||||
void Open(const char *aFilename);
|
||||
|
||||
/**
|
||||
* Closes the pcap file.
|
||||
* Closes the pcapng file.
|
||||
*/
|
||||
void Close(void);
|
||||
|
||||
/**
|
||||
* Writes a frame to the pcap file.
|
||||
* Writes a frame to the pcapng file.
|
||||
*
|
||||
* @param[in] aFrame The frame to write.
|
||||
* @param[in] aTimeUs The timestamp in microseconds.
|
||||
@@ -64,11 +64,14 @@ public:
|
||||
void WriteFrame(const otRadioFrame &aFrame, uint64_t aTimeUs);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kPcapMagicNumber = 0xa1b2c3d4;
|
||||
static constexpr uint16_t kPcapVersionMajor = 2;
|
||||
static constexpr uint16_t kPcapVersionMinor = 4;
|
||||
static constexpr uint32_t kPcapSnapLen = 65535;
|
||||
static constexpr uint32_t kPcapDlt154Tap = 283;
|
||||
static constexpr uint32_t kPcapngShbType = 0x0a0d0d0a;
|
||||
static constexpr uint32_t kPcapngByteOrderMagic = 0x1a2b3c4d;
|
||||
static constexpr uint16_t kPcapngVersionMajor = 1;
|
||||
static constexpr uint16_t kPcapngVersionMinor = 0;
|
||||
static constexpr uint32_t kPcapngIdbType = 0x00000001;
|
||||
static constexpr uint32_t kPcapngEpbType = 0x00000006;
|
||||
static constexpr uint32_t kPcapngSnapLen = 65535;
|
||||
static constexpr uint32_t kPcapngLinkTypeIeee802154 = 283; // DLT_IEEE802_15_4_TAP
|
||||
|
||||
static constexpr uint8_t kTapVersion = 0;
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ run_test()
|
||||
|
||||
local test_name="nexus_${test_base}"
|
||||
local json_file="test_${test_full}.json"
|
||||
local pcap_file="test_${test_full}.pcap"
|
||||
local pcap_file="test_${test_full}.pcapng"
|
||||
local verify_script="${REPO_ROOT}/tests/nexus/verify_${test_base}.py"
|
||||
local nexus_bin="${NEXUS_BIN_DIR}/${test_name}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user