Skip to content

Commit

Permalink
timelimit for sendPakckets autotest stage. Packet receiving rewritten.
Browse files Browse the repository at this point in the history
New implementation bases on whole stage time limit (2s default equivalent of sum
of waits used before) instead of hardcoded 1s header wait and 1s body wait.

Fixes logic of expecting read call on SOCK_STREAM to return whole header in one
call and body on another single call.

Adds ability to override default 2s timelimit by adding a key-value pair
timelimit: <unsinged int seconds> in sendPackets stage YAML.
  • Loading branch information
vimes authored and GeorgyKirichenko committed Jul 4, 2024
1 parent 0b22386 commit e4e45b5
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 30 deletions.
94 changes: 67 additions & 27 deletions autotest/autotest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ struct __attribute__((__packed__)) packHeader
uint32_t data_length;
};

using namespace nAutotest;
namespace nAutotest
{

static const std::tuple<ip_address_t,
std::string,
Expand Down Expand Up @@ -277,20 +278,42 @@ void tAutotest::sendThread(std::string interfaceName,
pcap_close(pcap);
}

static bool readPacket(int fd, pcap_pkthdr* header, u_char* data)
bool readTimeLimited(int fd, u_char* buf, ssize_t len, std::chrono::system_clock::time_point time_to_give_up)
{
ssize_t ret = 0;
int i;

struct packHeader hdr;
for (i = 0; i < 1000; ++i)
while (len > 0 && std::chrono::system_clock::now() < time_to_give_up)
{
ret = read(fd, &hdr, sizeof(hdr));
if (ret >= 0)
break;
std::this_thread::sleep_for(std::chrono::microseconds{1000});
ret = read(fd, buf, len);
switch (ret)
{
case 0:
return false;
case -1:
if ((errno == EAGAIN) || (errno = EWOULDBLOCK))
{
std::this_thread::sleep_for(READ_WAIT_UNTIL_RETRY);
}
else
{
return false;
}
break;
default:
len -= ret;
buf += ret;
break;
}
}
if (ret <= 0)

return len == 0;
}

static bool readPacket(int fd, pcap_pkthdr* header, u_char* data, Duration timelimit)
{
auto time_to_give_up = std::chrono::system_clock::now() + timelimit;

struct packHeader hdr;
if (!readTimeLimited(fd, hdr, time_to_give_up))
{
return false;
}
Expand All @@ -303,19 +326,12 @@ static bool readPacket(int fd, pcap_pkthdr* header, u_char* data)
throw "";
}

for (; i < 1000; i++)
if (!readTimeLimited(fd, data, hdr.data_length, time_to_give_up))
{
ret = read(fd, data, hdr.data_length);
if (ret >= 0)
break;
std::this_thread::sleep_for(std::chrono::microseconds{1000});
}
if (ret <= 0)
{
YANET_LOG_ERROR("error: read bytes %d: %s\n", hdr.data_length, strerror(errno));
return false;
}
header->len = ret;

header->len = hdr.data_length;
header->caplen = header->len;
return true;
}
Expand Down Expand Up @@ -442,7 +458,7 @@ void tAutotest::dumpThread(std::string interfaceName,

for (;;)
{
if (!readPacket(iface, &tmp_pcap_packetHeader, buffer))
if (!readPacket(iface, &tmp_pcap_packetHeader, buffer, DEFAULT_PACKET_READ_TIME_LIMIT))
{
break;
}
Expand Down Expand Up @@ -558,7 +574,8 @@ class pcap_expectation
};

void tAutotest::recvThread(std::string interfaceName,
std::vector<std::string> expectFilePaths)
std::vector<std::string> expectFilePaths,
Duration timelimit)
{
PcapDumper pcapDumper(std::tmpnam(nullptr) + std::string(".pcap"));

Expand All @@ -570,6 +587,13 @@ void tAutotest::recvThread(std::string interfaceName,

TextDumper dumper;

if (timelimit > WARN_WAIT_THRESHOLD)
{
YANET_LOG_INFO("Will wait for packets for %lu seconds.\n",
std::chrono::duration_cast<std::chrono::seconds>(timelimit).count());
}
auto time_to_give_up = std::chrono::system_clock::now() + timelimit;

auto iface = pcaps[interfaceName];
bool success = true;
uint64_t packetsCount = 0;
Expand All @@ -578,7 +602,13 @@ void tAutotest::recvThread(std::string interfaceName,
u_char buffer[MAX_PACK_LEN];
pcap_pkthdr tmp_pcap_packetHeader;

if (!readPacket(iface, &tmp_pcap_packetHeader, buffer))
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 "";
}
if (!readPacket(iface, &tmp_pcap_packetHeader, buffer, time_to_give_up - now))
{
std::stringstream buf;
bool not_first = false;
Expand Down Expand Up @@ -674,7 +704,7 @@ void tAutotest::recvThread(std::string interfaceName,
u_char buffer[MAX_PACK_LEN];
pcap_pkthdr tmp_pcap_packetHeader;

if (!readPacket(iface, &tmp_pcap_packetHeader, buffer))
if (!readPacket(iface, &tmp_pcap_packetHeader, buffer, DEFAULT_PACKET_READ_TIME_LIMIT))
{
break;
}
Expand Down Expand Up @@ -910,10 +940,18 @@ bool tAutotest::step_sendPackets(const YAML::Node& yamlStep,
paths.push_back(path + "/" + yamlExpect.as<std::string>());
}

threads.emplace_back([this, &success, interfaceName, paths]() {
Duration timelimit = DEFAULT_STEP_TIME_LIMIT;
auto& yamlTimelimit = yamlPort["timelimit"];
if (yamlTimelimit)
{
using namespace std::chrono;
timelimit = duration_cast<Duration>(seconds{yamlTimelimit.as<unsigned int>()});
}

threads.emplace_back([this, &success, interfaceName, paths, timelimit]() {
try
{
recvThread(interfaceName, paths);
recvThread(interfaceName, paths, timelimit);
}
catch (...)
{
Expand Down Expand Up @@ -1974,3 +2012,5 @@ void tAutotest::fflushSharedMemory()
void* memaddr = std::get<1>(rawShmInfo);
memset(memaddr, 0, size);
}

} // namespace autotest
21 changes: 18 additions & 3 deletions autotest/autotest.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include "common/idataplane.h"
#include "common/result.h"

namespace nAutotest
{

using ipv4_address_t = common::ipv4_address_t;
using ipv6_address_t = common::ipv6_address_t;
using ip_address_t = common::ip_address_t;
Expand All @@ -21,8 +24,12 @@ using ip_prefix_t = common::ip_prefix_t;
using community_t = common::community_t;
using large_community_t = common::large_community_t;

namespace nAutotest
{
using namespace std::chrono_literals;
using Duration = std::chrono::system_clock::duration;
inline constexpr Duration DEFAULT_PACKET_READ_TIME_LIMIT = 2s;
inline constexpr Duration DEFAULT_STEP_TIME_LIMIT = 2s;
inline constexpr Duration READ_WAIT_UNTIL_RETRY = 1000us;
inline constexpr Duration WARN_WAIT_THRESHOLD = 10s;

class tAutotest
{
Expand All @@ -39,7 +46,7 @@ class tAutotest

protected:
void sendThread(std::string interfaceName, std::string sendFilePath);
void recvThread(std::string interfaceName, std::vector<std::string> expectFilePaths);
void recvThread(std::string interfaceName, std::vector<std::string> expectFilePaths, Duration timelimit);
void dumpThread(std::string interfaceName, std::string dumpFilePath);

bool step_ipv4Update(const YAML::Node& yamlStep);
Expand Down Expand Up @@ -122,4 +129,12 @@ class tAutotest
uint64_t memorized_counter_value;
};

bool readTimeLimited(int fd, u_char* data, ssize_t len, std::chrono::system_clock::time_point time_to_give_up);

template<typename T>
bool readTimeLimited(int fd, T& data, std::chrono::system_clock::time_point time_to_give_up)
{
return readTimeLimited(fd, reinterpret_cast<u_char*>(&data), sizeof(data), time_to_give_up);
}

}

0 comments on commit e4e45b5

Please sign in to comment.