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

Nanosec accurate packet processing #796

Merged
Changes from 2 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
2 changes: 1 addition & 1 deletion src/common/timer.c
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ init_timestamp(struct timespec *timestamp)
}

int get_current_time(struct timespec *ts){
#ifdef _POSIX_C_SOURCE >= 199309L
#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L
return clock_gettime(CLOCK_REALTIME, ts);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't looked at this closely, but would this work with CLOCK_MONOTONIC? It would not be susceptible to NTP, but would not work if real-time clocks are needed.

Copy link
Contributor Author

@plangarbalint plangarbalint May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using CLOCK_MONOTONIC is also possible, I fixed it in a new commit. I also had to modify gettimeofday_sleep function to work properly with CLOCK_MONOTONIC

Copy link

@SPYFF SPYFF May 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the PR also using absolute time semantics for more precise sleeping, both CLOCK_MONOTONIC and CLOCK_REALTIME would work. However AFAIK POSIX only defines CLOCK_REALTIME mandatory. Probably every sane OS implements both clocksource, but I think realtime chosen here because of portability concerns.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll put it through it's paces when I start work on versin 4.5. I'll see if I can get my confidence up that it won't affect IoT and oldert stuff.

#else
struct timeval tv;
7 changes: 7 additions & 0 deletions src/defines.h.in
Original file line number Diff line number Diff line change
@@ -358,6 +358,13 @@ typedef u_int32_t uint32_t
(a)->tv_nsec = (b)->tv_nsec; \
} while(0)

/* libpcap puts nanosec values in tv_usec when pcap file is read with nanosec precision*/
#define TIMEVAL_AS_TIMESPEC_SET(a, b) \
do { \
(a)->tv_sec = (b)->tv_sec; \
(a)->tv_nsec = (b)->tv_usec; \
} while(0)

/*
* Help suppress some compiler warnings
* No problem if variable is actually used
18 changes: 9 additions & 9 deletions src/replay.c
Original file line number Diff line number Diff line change
@@ -125,7 +125,7 @@ replay_file(tcpreplay_t *ctx, int idx)

/* read from pcap file if we haven't cached things yet */
if (!ctx->options->preload_pcap) {
if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
if ((pcap = pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf)) == NULL) {
tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
return -1;
}
@@ -140,10 +140,10 @@ replay_file(tcpreplay_t *ctx, int idx)

} else {
if (!ctx->options->file_cache[idx].cached) {
if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
return -1;
}
if ((pcap = pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf)) == NULL) {
tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
return -1;
}
ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
}
}
@@ -152,10 +152,10 @@ replay_file(tcpreplay_t *ctx, int idx)
if (ctx->options->verbose) {
/* in cache mode, we may not have opened the file */
if (pcap == NULL)
if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
return -1;
}
if ((pcap = pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf)) == NULL) {
tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
return -1;
}

ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
/* init tcpdump */
32 changes: 16 additions & 16 deletions src/send_packets.c
Original file line number Diff line number Diff line change
@@ -316,8 +316,7 @@ static void increment_iteration(tcpreplay_t *ctx)
void
send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
{
struct timeval last_pkt_ts;
struct timespec now, print_delta;
struct timespec now, print_delta, last_pkt_ts, pkthdr_ts;
tcpreplay_opt_t *options = ctx->options;
tcpreplay_stats_t *stats = &ctx->stats;
COUNTER packetnum = 0;
@@ -350,7 +349,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
}

ctx->skip_packets = 0;
timerclear(&last_pkt_ts);
timesclear(&last_pkt_ts);
if (options->limit_time > 0)
end_us = TIMESPEC_TO_MICROSEC(&stats->start_time) +
SEC_TO_MICROSEC(options->limit_time);
@@ -369,7 +368,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
*/
while (!ctx->abort &&
(pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) {

TIMEVAL_AS_TIMESPEC_SET(&pkthdr_ts, &pkthdr.ts); // libpcap puts nanosec values in tv_usec
now_is_now = false;
packetnum++;
#if defined TCPREPLAY || defined TCPREPLAY_EDIT
@@ -429,20 +428,20 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
* time stamping is expensive, but now is the
* time to do it.
*/
dbgx(4, "This packet time: " TIMEVAL_FORMAT, pkthdr.ts.tv_sec,
pkthdr.ts.tv_usec);
dbgx(4, "This packet time: " TIMESPEC_FORMAT, pkthdr_ts.tv_sec,
pkthdr_ts.tv_nsec);
skip_length = 0;
ctx->skip_packets = 0;

if (options->speed.mode == speed_multiplier) {
if (!timerisset(&last_pkt_ts)) {
TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts);
} else if (timercmp(&pkthdr.ts, &last_pkt_ts, >)) {
struct timeval delta;

timersub(&pkthdr.ts, &last_pkt_ts, &delta);
timeradd_timeval_timespec(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta);
TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts);
if (!timesisset(&last_pkt_ts)) {
TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts);
} else if (timescmp(&pkthdr_ts, &last_pkt_ts, >)) {
struct timespec delta;

timessub(&pkthdr_ts, &last_pkt_ts, &delta);
timeradd_timespec(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta);
TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts);
}
}

@@ -999,7 +998,7 @@ static void calc_sleep_time(tcpreplay_t *ctx, struct timespec *pkt_ts_delta,
if (timescmp(pkt_ts_delta, time_delta, >)) {
/* pkt_time_delta has increased, so handle normally */
timessub(pkt_ts_delta, time_delta, &nap_for);
TIMESPEC_SET(&nap_for, &ctx->nap);
TIMESPEC_SET(&ctx->nap, &nap_for);
dbgx(3, "original packet delta time: " TIMESPEC_FORMAT,
ctx->nap.tv_sec, ctx->nap.tv_nsec);
timesdiv_float(&ctx->nap, options->speed.multiplier);
@@ -1117,8 +1116,9 @@ static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp,


/* don't sleep if nap = {0, 0} */
if (!timesisset(nap_this_time))
if (!timesisset(nap_this_time)){
return;
}

/* do we need to limit the total time we sleep? */
if (timesisset(&(options->maxsleep)) && (timescmp(nap_this_time, &(options->maxsleep), >))) {
2 changes: 1 addition & 1 deletion src/sleep.h
Original file line number Diff line number Diff line change
@@ -57,9 +57,9 @@ static inline void
nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap,
struct timespec *now, bool flush _U_)
{
#ifdef _POSIX_C_SOURCE >= 200112L
struct timespec sleep_until;
timeradd_timespec(now, nap, &sleep_until);
#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_until, NULL);
#else
nanosleep(nap, NULL);