Skip to content

Commit

Permalink
Feature #796: fix netmap, get_current_time etc.
Browse files Browse the repository at this point in the history
* macOS was not reading nanosecond timer
* get time called too often, causing overhead
* fine tune gettimeofday_sleep()
* adjusted overflow value to prevent issues with very long running instances
* fix build/merge issues
  • Loading branch information
fklassen committed Dec 26, 2023
1 parent f9e2f70 commit b860e37
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 74 deletions.
15 changes: 14 additions & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortEnumsOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
Expand All @@ -16,7 +18,7 @@ AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros: ['__capability', '__output', '__ununsed', '_U_']
AttributeMacros: ['__capability', '__output', '__unused', '_U_']
BinPackArguments: false
BinPackParameters: false
BitFieldColonSpacing: None
Expand All @@ -28,9 +30,11 @@ BraceWrapping:
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
Expand Down Expand Up @@ -69,7 +73,12 @@ IncludeCategories:
Priority: 6
IndentGotoLabels: false
IndentPPDirectives: None
IndentRequiresClause: false
IndentExternBlock: AfterExternBlock
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: true
InsertTrailingCommas: None
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
Expand All @@ -86,12 +95,16 @@ SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 8
Expand Down
1 change: 1 addition & 0 deletions docs/CREDIT
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,5 @@ Bastian Triller <GitHub @btriller>
- Linux SLL2

GithHub @plangarbalint
- eBPF
- nanosecond timers
2 changes: 1 addition & 1 deletion src/common/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ init_timestamp(struct timespec *timestamp)
int
get_current_time(struct timespec *ts)
{
#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L
#if defined CLOCK_MONOTONIC || defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L
return clock_gettime(CLOCK_MONOTONIC, ts);
#else
struct timeval tv;
Expand Down
4 changes: 1 addition & 3 deletions src/common/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,4 @@ void timesdiv_float(struct timespec *tvs, float div);
typedef struct timeval timestamp_t;

void init_timestamp(struct timespec *timestamp);
int get_current_time(struct timespec *ts);

#endif /* _TIMER_H_ */
int get_current_time(struct timespec *timestamp);
4 changes: 2 additions & 2 deletions src/common/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ format_date_time(struct timespec *when, char *buf, size_t len)
if (!tm)
return -1;

strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%06u", tm);
return snprintf(buf, len, tmp, when->tv_nsec / 1000);
strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%09u", tm);
return snprintf(buf, len, tmp, when->tv_nsec);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/defines.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ char dummy[0];
#define COUNTER unsigned long
#define COUNTER_SPEC "%lu"
#endif
#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 20)
#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 23)

#include <common/cidr.h>
#include <common/list.h>
Expand Down
31 changes: 13 additions & 18 deletions src/send_packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ extern tcpedit_t *tcpedit;
#include "send_packets.h"
#include "sleep.h"

#ifdef DEBUG
extern int debug;
#endif

static void calc_sleep_time(tcpreplay_t *ctx,
struct timespec *pkt_time,
struct timespec *last,
Expand All @@ -70,8 +66,11 @@ static void calc_sleep_time(tcpreplay_t *ctx,
COUNTER start_us,
COUNTER *skip_length);
static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp _U_, struct timespec *nap_this_time, struct timespec *now);
static u_char *
get_next_packet(tcpreplay_t *ctx, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int file_idx, packet_cache_t **prev_packet);
static u_char *get_next_packet(tcpreplay_opt_t *options,
pcap_t *pcap,
struct pcap_pkthdr *pkthdr,
int file_idx,
packet_cache_t **prev_packet);
static uint32_t get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter);

#ifdef HAVE_NETMAP
Expand Down Expand Up @@ -336,7 +335,7 @@ increment_iteration(tcpreplay_t *ctx)
void
send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
{
struct timespec now, print_delta, last_pkt_ts, pkthdr_ts;
struct timespec now, print_delta, last_pkt_ts;
tcpreplay_opt_t *options = ctx->options;
tcpreplay_stats_t *stats = &ctx->stats;
COUNTER packetnum = 0;
Expand Down Expand Up @@ -386,7 +385,9 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
* Keep sending while we have packets or until
* we've sent enough packets
*/
while (!ctx->abort && (pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) {
while (!ctx->abort && read_next_packet &&
(pktdata = get_next_packet(options, pcap, &pkthdr, idx, prev_packet)) != NULL) {
struct timespec pkthdr_ts;
TIMEVAL_AS_TIMESPEC_SET(&pkthdr_ts, &pkthdr.ts); // libpcap puts nanosec values in tv_usec
now_is_now = false;
packetnum++;
Expand Down Expand Up @@ -480,6 +481,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
&stats->end_time,
TIMESPEC_TO_NANOSEC(&stats->start_time),
&skip_length);

/*
* Track the time of the "last packet sent".
*
Expand Down Expand Up @@ -1033,12 +1035,6 @@ calc_sleep_time(tcpreplay_t *ctx,
if (timescmp(pkt_ts_delta, time_delta, >)) {
/* pkt_time_delta has increased, so handle normally */
timessub(pkt_ts_delta, time_delta, &nap_for);
// printf("pkt_ts_delta sec: %lu\n", pkt_ts_delta->tv_sec);
// printf("pkt_ts_delta nsec: %lu\n", pkt_ts_delta->tv_nsec);
// printf("time_delta sec: %lu\n", time_delta->tv_sec);
// printf("time_delta nsec: %lu\n", time_delta->tv_nsec);
// printf("nap_for sec: %lu\n", nap_for.tv_sec);
// printf("nap_for nsec: %lu\n", nap_for.tv_nsec);
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);
Expand All @@ -1055,15 +1051,15 @@ calc_sleep_time(tcpreplay_t *ctx,
if (now_ns) {
COUNTER next_tx_ns;
COUNTER bps = options->speed.speed;
COUNTER bits_sent = ((ctx->stats.bytes_sent + len) * 8); // PB: Ferencol miert bits sent?
COUNTER bits_sent = ((ctx->stats.bytes_sent + len) * 8);
COUNTER tx_ns = now_ns - start_ns;

/*
* bits * 1000000000 divided by bps = nanosecond
*
* ensure there is no overflow in cases where bits_sent is very high
*/
if (bits_sent > COUNTER_OVERFLOW_RISK && bps > 500000)
if (bits_sent > COUNTER_OVERFLOW_RISK)
next_tx_ns = (bits_sent * 1000) / bps * 1000000;
else
next_tx_ns = (bits_sent * 1000000000) / bps;
Expand Down Expand Up @@ -1154,9 +1150,8 @@ tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp, struct timespec *nap_this_time, s
#endif

/* 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), >))) {
Expand Down
2 changes: 1 addition & 1 deletion src/signal_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <sys/time.h>
#include <unistd.h>

struct timeval suspend_time; // PB: do we need to modify this part of the code?
struct timeval suspend_time;
static struct timeval suspend_start;
static struct timeval suspend_end;

Expand Down
6 changes: 0 additions & 6 deletions src/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,4 @@ ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap _U_, struct timesp
#else
err(-1, "Platform does not support IO Port for timing");
#endif

#ifdef HAVE_NETMAP
if (flush)
ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
#endif /* HAVE_NETMAP */
get_current_time(now);
}
29 changes: 13 additions & 16 deletions src/sleep.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@
static inline void
nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespec *now, bool flush _U_)
{
#if defined _POSIX_C_SOURCE && _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_MONOTONIC, TIMER_ABSTIME, &sleep_until, NULL);
#else
nanosleep(nap, NULL);
Expand All @@ -77,36 +77,36 @@ nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespe
* Note: make sure "now" has recently been updated.
*/
static inline void
gettimeofday_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timespec *now, bool flush _U_)
gettimeofday_sleep(sendpacket_t *sp, struct timespec *nap, struct timespec *now, bool flush _U_)
{
struct timeval now_ms, sleep_until, nap_for, last;
TIMESPEC_TO_TIMEVAL(&nap_for, nap);
gettimeofday(&now_ms, NULL);
struct timespec sleep_until;
#ifdef HAVE_NETMAP
struct timespec last;
uint32_t i = 0;
TIMEVAL_SET(&last, &now_ms);

TIMESPEC_SET(&last, now);
#endif /* HAVE_NETMAP */

timeradd(&now_ms, &nap_for, &sleep_until);
timeradd_timespec(now, nap, &sleep_until);

while (!sp->abort) {
#ifdef HAVE_NETMAP
if (flush && timercmp(&now_ms, &last, !=)) {
TIMESPEC_SET(&last, &now_ms);
if (flush && timescmp(now, &last, !=)) {
TIMESPEC_SET(&last, now);
if ((++i & 0xf) == 0)
/* flush TX buffer every 16 usec */
ioctl(sp->handle.fd, NIOCTXSYNC, NULL);
}
#endif /* HAVE_NETMAP */
if (timercmp(&now_ms, &sleep_until, >=))
if (timescmp(now, &sleep_until, >=))
break;

#ifdef HAVE_SCHED_H
/* yield the CPU so other apps remain responsive */
sched_yield();
#endif
gettimeofday(&now_ms, NULL);
get_current_time(now);
}
get_current_time(now);
}

#ifdef HAVE_SELECT
Expand All @@ -120,8 +120,6 @@ static inline void
select_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timespec *now_ns, bool flush _U_)
{
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
#ifdef HAVE_NETMAP
if (flush)
ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
Expand All @@ -136,6 +134,7 @@ select_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timespec *now_ns
if (flush)
ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
#endif

get_current_time(now_ns);
}
#endif /* HAVE_SELECT */
Expand All @@ -152,5 +151,3 @@ select_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timespec *now_ns
void ioport_sleep_init(void);

void ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespec *now, bool flush);

#endif /* __SLEEP_H__ */
49 changes: 26 additions & 23 deletions src/tcpreplay_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc)

options->loop = OPT_VALUE_LOOP;
options->loopdelay_ms = OPT_VALUE_LOOPDELAY_MS;
options->loopdelay_ns = OPT_VALUE_LOOPDELAY_NS;

if (HAVE_OPT(LIMIT))
options->limit_send = OPT_VALUE_LIMIT;
Expand Down Expand Up @@ -314,7 +315,6 @@ tcpreplay_post_args(tcpreplay_t *ctx, int argc)
options->accurate = accurate_gtod;
} else if (strcmp(OPT_ARG(TIMER), "nano") == 0) {
options->accurate = accurate_nanosleep;
options->loopdelay_ns = OPT_VALUE_LOOPDELAY_NS;
} else if (strcmp(OPT_ARG(TIMER), "abstime") == 0) {
tcpreplay_seterr(ctx, "%s", "abstime is deprecated");
ret = -1;
Expand Down Expand Up @@ -1120,6 +1120,7 @@ tcpreplay_prepare(tcpreplay_t *ctx)
return ret;
}

static bool apply_loop_delay(tcpreplay_t *ctx);
/**
* \brief sends the traffic out the interfaces
*
Expand Down Expand Up @@ -1167,12 +1168,12 @@ tcpreplay_replay(tcpreplay_t *ctx)
loop, total_loops,
ctx->unique_iteration);
}
if ((rcode = tcpr_replay_index(ctx)) < 0) {
if ((rcode = tcpr_replay_index(ctx)) < 0)
return rcode;
}
if (ctx->options->loop > 0) {
apply_loop_delay(ctx);
get_current_time(&ctx->stats.end_time);
if (apply_loop_delay(ctx))
get_current_time(&ctx->stats.end_time);

if (ctx->options->stats == 0) {
packet_stats(&ctx->stats);
}
Expand All @@ -1195,11 +1196,12 @@ tcpreplay_replay(tcpreplay_t *ctx)
printf("Loop " COUNTER_SPEC " (" COUNTER_SPEC " unique)...\n", loop,
ctx->unique_iteration);
}
if ((rcode = tcpr_replay_index(ctx)) < 0) {
if ((rcode = tcpr_replay_index(ctx)) < 0)
return rcode;
}
apply_loop_delay(ctx);
get_current_time(&ctx->stats.end_time);

if (apply_loop_delay(ctx))
get_current_time(&ctx->stats.end_time);

if (ctx->options->stats == 0 && !ctx->abort)
packet_stats(&ctx->stats);
}
Expand Down Expand Up @@ -1381,19 +1383,20 @@ int tcpreplay_get_flow_expiry(tcpreplay_t *ctx)
return ctx->options->flow_expiry;
}

void
apply_loop_delay(tcpreplay_t *ctx)
{
if (ctx->options->accurate == accurate_nanosleep) {
if (!ctx->abort && ctx->options->loopdelay_ns > 0) {
struct timespec nap;
nap.tv_sec = 0;
nap.tv_nsec = ctx->options->loopdelay_ns;
nanosleep_sleep(NULL, &nap, &ctx->stats.end_time, NULL);
}
} else {
if (!ctx->abort && ctx->options->loopdelay_ms > 0) {
usleep(ctx->options->loopdelay_ms * 1000);
}
bool
apply_loop_delay(tcpreplay_t *ctx) {
if (!ctx->abort && ctx->options->loopdelay_ms > 0) {
usleep(ctx->options->loopdelay_ms * 1000);
return true;
}

if (!ctx->abort && ctx->options->loopdelay_ns > 0) {
struct timespec nap;
nap.tv_sec = 0;
nap.tv_nsec = ctx->options->loopdelay_ns;
nanosleep_sleep(NULL, &nap, &ctx->stats.end_time, NULL);
return true;
}

return false;
}
Loading

0 comments on commit b860e37

Please sign in to comment.