Skip to content

Commit

Permalink
Merge pull request #836 from appneta/Feature_#796_nanosecond_packet_p…
Browse files Browse the repository at this point in the history
…rocessing

Feature #796 - nanosecond packet processing
  • Loading branch information
fklassen authored Dec 29, 2023
2 parents 5fdcd2e + 3f1a891 commit 0dc684a
Show file tree
Hide file tree
Showing 20 changed files with 310 additions and 224 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/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
09/03/2023 Version 4.5.0-beta1
- handle IPv6 fragment extension header (#832 #837)
- nanosecond timestamps (#796)
- low PPS values run at full speed after several days (#779)
- create DLT_LINUX_SLL2 plugin (#727)

Expand Down
7 changes: 6 additions & 1 deletion docs/CREDIT
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,9 @@ David Guti <GitHub @david-guti>
Bastian Triller <GitHub @btriller>
- Linux SLL2

Chuck Cottrill <GitHub @ChuckCottrill>
GithHub @plangarbalint
- eBPF
- nanosecond timers

Chuck Cottrill <GitHub @ChuckCottrill>
- handle IPv6 fragment extensions
4 changes: 2 additions & 2 deletions src/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ do_bridge(tcpbridge_opt_t *options, tcpedit_t *tcpedit)
do_bridge_bidirectional(options, tcpedit);
}

if (gettimeofday(&stats.end_time, NULL) < 0)
errx(-1, "gettimeofday() failed: %s", strerror(errno));
if (get_current_time(&stats.end_time) < 0)
errx(-1, "get_current_time() failed: %s", strerror(errno));
packet_stats(&stats);
}

Expand Down
19 changes: 16 additions & 3 deletions src/common/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "config.h"
#include <stdlib.h>

/* Miscellaneous timeval routines */
/* Miscellaneous timeval/timespec routines */

/* Divide tvs by div, storing the result in tvs */
void
Expand All @@ -39,7 +39,20 @@ timesdiv_float(struct timespec *tvs, float div)
}

void
init_timestamp(timestamp_t *ctx)
init_timestamp(struct timespec *timestamp)
{
timerclear(ctx);
timesclear(timestamp);
}

int
get_current_time(struct timespec *ts)
{
#if defined CLOCK_MONOTONIC || defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L
return clock_gettime(CLOCK_MONOTONIC, ts);
#else
struct timeval tv;
int success = gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, ts);
return success;
#endif
}
30 changes: 29 additions & 1 deletion src/common/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,33 @@ void timesdiv_float(struct timespec *tvs, float div);
} while (0)
#endif

/* add tvp and uvp and store in vvp */
#ifndef timeradd_timespec
#define timeradd_timespec(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_nsec = (tvp)->tv_nsec + (uvp)->tv_nsec; \
if ((vvp)->tv_nsec >= 1000000000) { \
(vvp)->tv_sec++; \
(vvp)->tv_nsec -= 1000000000; \
} \
} while (0)
#endif

/* add tvp and uvp and store in vvp */
#ifndef timeradd_timeval_timespec
#define timeradd_timeval_timespec(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_nsec = (tvp)->tv_nsec + (uvp)->tv_usec * 1000; \
if ((vvp)->tv_nsec >= 1000000000) { \
int seconds = (vvp)->tv_nsec % 1000000000; \
(vvp)->tv_sec += seconds; \
(vvp)->tv_nsec -= 1000000000 * seconds; \
} \
} while (0)
#endif

/* subtract uvp from tvp and store in vvp */
#ifndef timersub
#define timersub(tvp, uvp, vvp) \
Expand Down Expand Up @@ -150,4 +177,5 @@ void timesdiv_float(struct timespec *tvs, float div);

typedef struct timeval timestamp_t;

void init_timestamp(timestamp_t *ctx);
void init_timestamp(struct timespec *timestamp);
int get_current_time(struct timespec *timestamp);
21 changes: 11 additions & 10 deletions src/common/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ our_safe_pcap_next_ex(pcap_t *pcap,
void
packet_stats(const tcpreplay_stats_t *stats)
{
struct timeval diff;
struct timespec diff;
COUNTER diff_us;
COUNTER bytes_sec = 0;
u_int32_t bytes_sec_10ths = 0;
Expand All @@ -221,8 +221,8 @@ packet_stats(const tcpreplay_stats_t *stats)
COUNTER pkts_sec = 0;
u_int32_t pkts_sec_100ths = 0;

timersub(&stats->end_time, &stats->start_time, &diff);
diff_us = TIMEVAL_TO_MICROSEC(&diff);
timessub(&stats->end_time, &stats->start_time, &diff);
diff_us = TIMESPEC_TO_MICROSEC(&diff);

if (diff_us && stats->pkts_sent && stats->bytes_sent) {
COUNTER bytes_sec_X10;
Expand Down Expand Up @@ -251,18 +251,19 @@ packet_stats(const tcpreplay_stats_t *stats)
pkts_sec_100ths = pkts_sec_X100 % 100;
}

if (diff_us >= 1000 * 1000)
if (diff_us >= 1000 * 1000) {
printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%02zd seconds\n",
stats->pkts_sent,
stats->bytes_sent,
(ssize_t)diff.tv_sec,
(ssize_t)(diff.tv_usec / (10 * 1000)));
else
(ssize_t)(diff.tv_nsec / (10 * 1000000)));
} else {
printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%06zd seconds\n",
stats->pkts_sent,
stats->bytes_sent,
(ssize_t)diff.tv_sec,
(ssize_t)diff.tv_usec);
(ssize_t)diff.tv_nsec / 1000);
}

if (mb_sec >= 1)
printf("Rated: %llu.%1u Bps, %llu.%02u Mbps, %llu.%02u pps\n",
Expand Down Expand Up @@ -295,7 +296,7 @@ packet_stats(const tcpreplay_stats_t *stats)
* @return: string containing date, or -1 on error
*/
int
format_date_time(struct timeval *when, char *buf, size_t len)
format_date_time(struct timespec *when, char *buf, size_t len)
{
struct tm *tm;
char tmp[64];
Expand All @@ -306,8 +307,8 @@ format_date_time(struct timeval *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_usec);
strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%09u", tm);
return snprintf(buf, len, tmp, when->tv_nsec);
}

/**
Expand Down
12 changes: 6 additions & 6 deletions src/common/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ typedef struct {
COUNTER bytes_sent;
COUNTER pkts_sent;
COUNTER failed;
struct timeval start_time;
struct timeval time_delta;
struct timeval end_time;
struct timeval pkt_ts_delta;
struct timeval last_print;
struct timespec start_time;
struct timespec time_delta;
struct timespec end_time;
struct timespec pkt_ts_delta;
struct timespec last_print;
COUNTER flow_non_flow_packets;
COUNTER flows;
COUNTER flows_unique;
Expand All @@ -44,7 +44,7 @@ typedef struct {

int read_hexstring(const char *l2string, u_char *hex, int hexlen);
void packet_stats(const tcpreplay_stats_t *stats);
int format_date_time(struct timeval *when, char *buf, size_t len);
int format_date_time(struct timespec *when, char *buf, size_t len);
uint32_t tcpr_random(uint32_t *seed);
void restore_stdin(void);

Expand Down
16 changes: 11 additions & 5 deletions 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 Expand Up @@ -315,10 +315,9 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t
#define MICROSEC_TO_SEC(x) (x / 1000000)
#define NANOSEC_TO_SEC(x) ((u_int64_t)x / 1000000000)

#define TIMEVAL_TO_MILLISEC(x) (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000))
#define TIMEVAL_TO_MICROSEC(x) (((x)->tv_sec * 1000000) + (x)->tv_usec)
#define TIMEVAL_TO_NANOSEC(x) ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000))
#define TIMSTAMP_TO_MICROSEC(x) (TIMEVAL_TO_MICROSEC(x))
#define TIMEVAL_TO_MILLISEC(x) (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000))
#define TIMEVAL_TO_MICROSEC(x) (((x)->tv_sec * 1000000) + (x)->tv_usec)
#define TIMEVAL_TO_NANOSEC(x) ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000))

#define MILLISEC_TO_TIMEVAL(x, tv) \
do { \
Expand Down Expand Up @@ -360,6 +359,13 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t 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
Expand Down
6 changes: 3 additions & 3 deletions src/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,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;
}
Expand All @@ -133,7 +133,7 @@ replay_file(tcpreplay_t *ctx, int idx)

} else {
if (!ctx->options->file_cache[idx].cached) {
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;
}
Expand All @@ -145,7 +145,7 @@ 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) {
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;
}
Expand Down
Loading

0 comments on commit 0dc684a

Please sign in to comment.