diff --git a/.clang-format b/.clang-format index 0b3aa238..56e516cd 100644 --- a/.clang-format +++ b/.clang-format @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/docs/CREDIT b/docs/CREDIT index 26583a35..d21aee22 100644 --- a/docs/CREDIT +++ b/docs/CREDIT @@ -118,4 +118,5 @@ Bastian Triller - Linux SLL2 GithHub @plangarbalint + - eBPF - nanosecond timers \ No newline at end of file diff --git a/src/common/timer.c b/src/common/timer.c index 60e10bf2..38e123f9 100755 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -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; diff --git a/src/common/timer.h b/src/common/timer.h index 0cf801fa..b4cbfa34 100755 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -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); diff --git a/src/common/utils.c b/src/common/utils.c index 8e69834e..520d40d2 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -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); } /** diff --git a/src/defines.h.in b/src/defines.h.in index fe776552..1975f053 100644 --- a/src/defines.h.in +++ b/src/defines.h.in @@ -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 #include diff --git a/src/send_packets.c b/src/send_packets.c index e8d41fbc..788341b4 100644 --- a/src/send_packets.c +++ b/src/send_packets.c @@ -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, @@ -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 @@ -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; @@ -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++; @@ -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". * @@ -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); @@ -1055,7 +1051,7 @@ 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; /* @@ -1063,7 +1059,7 @@ calc_sleep_time(tcpreplay_t *ctx, * * 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; @@ -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), >))) { diff --git a/src/signal_handler.c b/src/signal_handler.c index f8b85d9e..9bfd56ee 100644 --- a/src/signal_handler.c +++ b/src/signal_handler.c @@ -31,7 +31,7 @@ #include #include -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; diff --git a/src/sleep.c b/src/sleep.c index 16234a43..27e3e85f 100644 --- a/src/sleep.c +++ b/src/sleep.c @@ -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); } diff --git a/src/sleep.h b/src/sleep.h index 71365ab5..ee12d8d2 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -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); @@ -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 @@ -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 */ @@ -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 */ @@ -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__ */ diff --git a/src/tcpreplay_api.c b/src/tcpreplay_api.c index 319ae109..453b92d7 100644 --- a/src/tcpreplay_api.c +++ b/src/tcpreplay_api.c @@ -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; @@ -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; @@ -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 * @@ -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); } @@ -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); } @@ -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; } diff --git a/src/tcpreplay_api.h b/src/tcpreplay_api.h index 321c8f18..6cff96b7 100644 --- a/src/tcpreplay_api.h +++ b/src/tcpreplay_api.h @@ -272,7 +272,6 @@ int tcpreplay_set_verbose(tcpreplay_t *, bool); int tcpreplay_set_tcpdump_args(tcpreplay_t *, char *); int tcpreplay_set_tcpdump(tcpreplay_t *, tcpdump_t *); -void apply_loop_delay(tcpreplay_t *ctx); /* * These functions are seen by the outside world, but nobody should ever use them * outside of internal tcpreplay API functions diff --git a/src/tcpreplay_opts.def b/src/tcpreplay_opts.def index a17dff73..e3536fde 100644 --- a/src/tcpreplay_opts.def +++ b/src/tcpreplay_opts.def @@ -320,6 +320,7 @@ flag = { flag = { name = loopdelay-ms; + flags-cant = loopdelay-ns; flags-must = loop; arg-type = number; arg-range = "0->"; @@ -330,7 +331,8 @@ flag = { flag = { name = loopdelay-ns; - flags-must = loop, timer; + flags-cant = loopdelay-ms; + flags-must = loop; arg-type = number; arg-range = "0->"; descrip = "Delay between loops in nanoseconds";