aboutsummaryrefslogtreecommitdiffstats
path: root/samples/bpf/xdpsock_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'samples/bpf/xdpsock_user.c')
-rw-r--r--samples/bpf/xdpsock_user.c366
1 files changed, 344 insertions, 22 deletions
diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c
index 49d7a6ad7e39..aa50864e4415 100644
--- a/samples/bpf/xdpsock_user.c
+++ b/samples/bpf/xdpsock_user.c
@@ -14,6 +14,7 @@
#include <arpa/inet.h>
#include <locale.h>
#include <net/ethernet.h>
+#include <netinet/ether.h>
#include <net/if.h>
#include <poll.h>
#include <pthread.h>
@@ -30,12 +31,16 @@
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
+#include <sched.h>
#include <bpf/libbpf.h>
#include <bpf/xsk.h>
#include <bpf/bpf.h>
#include "xdpsock.h"
+/* libbpf APIs for AF_XDP are deprecated starting from v0.7 */
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
#ifndef SOL_XDP
#define SOL_XDP 283
#endif
@@ -53,12 +58,27 @@
#define DEBUG_HEXDUMP 0
+#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */
+#define VLAN_PRIO_SHIFT 13
+#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
+#define VLAN_VID__DEFAULT 1
+#define VLAN_PRI__DEFAULT 0
+
+#define NSEC_PER_SEC 1000000000UL
+#define NSEC_PER_USEC 1000
+
+#define SCHED_PRI__DEFAULT 0
+
typedef __u64 u64;
typedef __u32 u32;
typedef __u16 u16;
typedef __u8 u8;
static unsigned long prev_time;
+static long tx_cycle_diff_min;
+static long tx_cycle_diff_max;
+static double tx_cycle_diff_ave;
+static long tx_cycle_cnt;
enum benchmark_type {
BENCH_RXDROP = 0,
@@ -78,14 +98,23 @@ static u32 opt_batch_size = 64;
static int opt_pkt_count;
static u16 opt_pkt_size = MIN_PKT_SIZE;
static u32 opt_pkt_fill_pattern = 0x12345678;
+static bool opt_vlan_tag;
+static u16 opt_pkt_vlan_id = VLAN_VID__DEFAULT;
+static u16 opt_pkt_vlan_pri = VLAN_PRI__DEFAULT;
+static struct ether_addr opt_txdmac = {{ 0x3c, 0xfd, 0xfe,
+ 0x9e, 0x7f, 0x71 }};
+static struct ether_addr opt_txsmac = {{ 0xec, 0xb1, 0xd7,
+ 0x98, 0x3a, 0xc0 }};
static bool opt_extra_stats;
static bool opt_quiet;
static bool opt_app_stats;
static const char *opt_irq_str = "";
static u32 irq_no;
static int irqs_at_init = -1;
+static u32 sequence;
static int opt_poll;
static int opt_interval = 1;
+static int opt_retries = 3;
static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP;
static u32 opt_umem_flags;
static int opt_unaligned_chunks;
@@ -97,6 +126,27 @@ static u32 opt_num_xsks = 1;
static u32 prog_id;
static bool opt_busy_poll;
static bool opt_reduced_cap;
+static clockid_t opt_clock = CLOCK_MONOTONIC;
+static unsigned long opt_tx_cycle_ns;
+static int opt_schpolicy = SCHED_OTHER;
+static int opt_schprio = SCHED_PRI__DEFAULT;
+static bool opt_tstamp;
+
+struct vlan_ethhdr {
+ unsigned char h_dest[6];
+ unsigned char h_source[6];
+ __be16 h_vlan_proto;
+ __be16 h_vlan_TCI;
+ __be16 h_vlan_encapsulated_proto;
+};
+
+#define PKTGEN_MAGIC 0xbe9be955
+struct pktgen_hdr {
+ __be32 pgh_magic;
+ __be32 seq_num;
+ __be32 tv_sec;
+ __be32 tv_usec;
+};
struct xsk_ring_stats {
unsigned long rx_npkts;
@@ -153,15 +203,63 @@ struct xsk_socket_info {
u32 outstanding_tx;
};
+static const struct clockid_map {
+ const char *name;
+ clockid_t clockid;
+} clockids_map[] = {
+ { "REALTIME", CLOCK_REALTIME },
+ { "TAI", CLOCK_TAI },
+ { "BOOTTIME", CLOCK_BOOTTIME },
+ { "MONOTONIC", CLOCK_MONOTONIC },
+ { NULL }
+};
+
+static const struct sched_map {
+ const char *name;
+ int policy;
+} schmap[] = {
+ { "OTHER", SCHED_OTHER },
+ { "FIFO", SCHED_FIFO },
+ { NULL }
+};
+
static int num_socks;
struct xsk_socket_info *xsks[MAX_SOCKS];
int sock;
+static int get_clockid(clockid_t *id, const char *name)
+{
+ const struct clockid_map *clk;
+
+ for (clk = clockids_map; clk->name; clk++) {
+ if (strcasecmp(clk->name, name) == 0) {
+ *id = clk->clockid;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int get_schpolicy(int *policy, const char *name)
+{
+ const struct sched_map *sch;
+
+ for (sch = schmap; sch->name; sch++) {
+ if (strcasecmp(sch->name, name) == 0) {
+ *policy = sch->policy;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
static unsigned long get_nsecs(void)
{
struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ clock_gettime(opt_clock, &ts);
return ts.tv_sec * 1000000000UL + ts.tv_nsec;
}
@@ -254,6 +352,15 @@ static void dump_app_stats(long dt)
xsks[i]->app_stats.prev_tx_wakeup_sendtos = xsks[i]->app_stats.tx_wakeup_sendtos;
xsks[i]->app_stats.prev_opt_polls = xsks[i]->app_stats.opt_polls;
}
+
+ if (opt_tx_cycle_ns) {
+ printf("\n%-18s %-10s %-10s %-10s %-10s %-10s\n",
+ "", "period", "min", "ave", "max", "cycle");
+ printf("%-18s %-10lu %-10lu %-10lu %-10lu %-10lu\n",
+ "Cyclic TX", opt_tx_cycle_ns, tx_cycle_diff_min,
+ (long)(tx_cycle_diff_ave / tx_cycle_cnt),
+ tx_cycle_diff_max, tx_cycle_cnt);
+ }
}
static bool get_interrupt_number(void)
@@ -737,29 +844,69 @@ static inline u16 udp_csum(u32 saddr, u32 daddr, u32 len,
#define ETH_FCS_SIZE 4
-#define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
- sizeof(struct udphdr))
+#define ETH_HDR_SIZE (opt_vlan_tag ? sizeof(struct vlan_ethhdr) : \
+ sizeof(struct ethhdr))
+#define PKTGEN_HDR_SIZE (opt_tstamp ? sizeof(struct pktgen_hdr) : 0)
+#define PKT_HDR_SIZE (ETH_HDR_SIZE + sizeof(struct iphdr) + \
+ sizeof(struct udphdr) + PKTGEN_HDR_SIZE)
+#define PKTGEN_HDR_OFFSET (ETH_HDR_SIZE + sizeof(struct iphdr) + \
+ sizeof(struct udphdr))
+#define PKTGEN_SIZE_MIN (PKTGEN_HDR_OFFSET + sizeof(struct pktgen_hdr) + \
+ ETH_FCS_SIZE)
#define PKT_SIZE (opt_pkt_size - ETH_FCS_SIZE)
-#define IP_PKT_SIZE (PKT_SIZE - sizeof(struct ethhdr))
+#define IP_PKT_SIZE (PKT_SIZE - ETH_HDR_SIZE)
#define UDP_PKT_SIZE (IP_PKT_SIZE - sizeof(struct iphdr))
-#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - sizeof(struct udphdr))
+#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - \
+ (sizeof(struct udphdr) + PKTGEN_HDR_SIZE))
static u8 pkt_data[XSK_UMEM__DEFAULT_FRAME_SIZE];
static void gen_eth_hdr_data(void)
{
- struct udphdr *udp_hdr = (struct udphdr *)(pkt_data +
+ struct pktgen_hdr *pktgen_hdr;
+ struct udphdr *udp_hdr;
+ struct iphdr *ip_hdr;
+
+ if (opt_vlan_tag) {
+ struct vlan_ethhdr *veth_hdr = (struct vlan_ethhdr *)pkt_data;
+ u16 vlan_tci = 0;
+
+ udp_hdr = (struct udphdr *)(pkt_data +
+ sizeof(struct vlan_ethhdr) +
+ sizeof(struct iphdr));
+ ip_hdr = (struct iphdr *)(pkt_data +
+ sizeof(struct vlan_ethhdr));
+ pktgen_hdr = (struct pktgen_hdr *)(pkt_data +
+ sizeof(struct vlan_ethhdr) +
+ sizeof(struct iphdr) +
+ sizeof(struct udphdr));
+ /* ethernet & VLAN header */
+ memcpy(veth_hdr->h_dest, &opt_txdmac, ETH_ALEN);
+ memcpy(veth_hdr->h_source, &opt_txsmac, ETH_ALEN);
+ veth_hdr->h_vlan_proto = htons(ETH_P_8021Q);
+ vlan_tci = opt_pkt_vlan_id & VLAN_VID_MASK;
+ vlan_tci |= (opt_pkt_vlan_pri << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
+ veth_hdr->h_vlan_TCI = htons(vlan_tci);
+ veth_hdr->h_vlan_encapsulated_proto = htons(ETH_P_IP);
+ } else {
+ struct ethhdr *eth_hdr = (struct ethhdr *)pkt_data;
+
+ udp_hdr = (struct udphdr *)(pkt_data +
+ sizeof(struct ethhdr) +
+ sizeof(struct iphdr));
+ ip_hdr = (struct iphdr *)(pkt_data +
+ sizeof(struct ethhdr));
+ pktgen_hdr = (struct pktgen_hdr *)(pkt_data +
sizeof(struct ethhdr) +
- sizeof(struct iphdr));
- struct iphdr *ip_hdr = (struct iphdr *)(pkt_data +
- sizeof(struct ethhdr));
- struct ethhdr *eth_hdr = (struct ethhdr *)pkt_data;
+ sizeof(struct iphdr) +
+ sizeof(struct udphdr));
+ /* ethernet header */
+ memcpy(eth_hdr->h_dest, &opt_txdmac, ETH_ALEN);
+ memcpy(eth_hdr->h_source, &opt_txsmac, ETH_ALEN);
+ eth_hdr->h_proto = htons(ETH_P_IP);
+ }
- /* ethernet header */
- memcpy(eth_hdr->h_dest, "\x3c\xfd\xfe\x9e\x7f\x71", ETH_ALEN);
- memcpy(eth_hdr->h_source, "\xec\xb1\xd7\x98\x3a\xc0", ETH_ALEN);
- eth_hdr->h_proto = htons(ETH_P_IP);
/* IP header */
ip_hdr->version = IPVERSION;
@@ -782,6 +929,9 @@ static void gen_eth_hdr_data(void)
udp_hdr->dest = htons(0x1000);
udp_hdr->len = htons(UDP_PKT_SIZE);
+ if (opt_tstamp)
+ pktgen_hdr->pgh_magic = htonl(PKTGEN_MAGIC);
+
/* UDP data */
memset32_htonl(pkt_data + PKT_HDR_SIZE, opt_pkt_fill_pattern,
UDP_PKT_DATA_SIZE);
@@ -905,6 +1055,7 @@ static struct option long_options[] = {
{"xdp-skb", no_argument, 0, 'S'},
{"xdp-native", no_argument, 0, 'N'},
{"interval", required_argument, 0, 'n'},
+ {"retries", required_argument, 0, 'O'},
{"zero-copy", no_argument, 0, 'z'},
{"copy", no_argument, 0, 'c'},
{"frame-size", required_argument, 0, 'f'},
@@ -913,10 +1064,20 @@ static struct option long_options[] = {
{"shared-umem", no_argument, 0, 'M'},
{"force", no_argument, 0, 'F'},
{"duration", required_argument, 0, 'd'},
+ {"clock", required_argument, 0, 'w'},
{"batch-size", required_argument, 0, 'b'},
{"tx-pkt-count", required_argument, 0, 'C'},
{"tx-pkt-size", required_argument, 0, 's'},
{"tx-pkt-pattern", required_argument, 0, 'P'},
+ {"tx-vlan", no_argument, 0, 'V'},
+ {"tx-vlan-id", required_argument, 0, 'J'},
+ {"tx-vlan-pri", required_argument, 0, 'K'},
+ {"tx-dmac", required_argument, 0, 'G'},
+ {"tx-smac", required_argument, 0, 'H'},
+ {"tx-cycle", required_argument, 0, 'T'},
+ {"tstamp", no_argument, 0, 'y'},
+ {"policy", required_argument, 0, 'W'},
+ {"schpri", required_argument, 0, 'U'},
{"extra-stats", no_argument, 0, 'x'},
{"quiet", no_argument, 0, 'Q'},
{"app-stats", no_argument, 0, 'a'},
@@ -940,6 +1101,7 @@ static void usage(const char *prog)
" -S, --xdp-skb=n Use XDP skb-mod\n"
" -N, --xdp-native=n Enforce XDP native mode\n"
" -n, --interval=n Specify statistics update interval (default 1 sec).\n"
+ " -O, --retries=n Specify time-out retries (1s interval) attempt (default 3).\n"
" -z, --zero-copy Force zero-copy mode.\n"
" -c, --copy Force copy mode.\n"
" -m, --no-need-wakeup Turn off use of driver need wakeup flag.\n"
@@ -949,6 +1111,7 @@ static void usage(const char *prog)
" -F, --force Force loading the XDP prog\n"
" -d, --duration=n Duration in secs to run command.\n"
" Default: forever.\n"
+ " -w, --clock=CLOCK Clock NAME (default MONOTONIC).\n"
" -b, --batch-size=n Batch size for sending or receiving\n"
" packets. Default: %d\n"
" -C, --tx-pkt-count=n Number of packets to send.\n"
@@ -957,6 +1120,15 @@ static void usage(const char *prog)
" (Default: %d bytes)\n"
" Min size: %d, Max size %d.\n"
" -P, --tx-pkt-pattern=nPacket fill pattern. Default: 0x%x\n"
+ " -V, --tx-vlan Send VLAN tagged packets (For -t|--txonly)\n"
+ " -J, --tx-vlan-id=n Tx VLAN ID [1-4095]. Default: %d (For -V|--tx-vlan)\n"
+ " -K, --tx-vlan-pri=n Tx VLAN Priority [0-7]. Default: %d (For -V|--tx-vlan)\n"
+ " -G, --tx-dmac=<MAC> Dest MAC addr of TX frame in aa:bb:cc:dd:ee:ff format (For -V|--tx-vlan)\n"
+ " -H, --tx-smac=<MAC> Src MAC addr of TX frame in aa:bb:cc:dd:ee:ff format (For -V|--tx-vlan)\n"
+ " -T, --tx-cycle=n Tx cycle time in micro-seconds (For -t|--txonly).\n"
+ " -y, --tstamp Add time-stamp to packet (For -t|--txonly).\n"
+ " -W, --policy=POLICY Schedule policy. Default: SCHED_OTHER\n"
+ " -U, --schpri=n Schedule priority. Default: %d\n"
" -x, --extra-stats Display extra statistics.\n"
" -Q, --quiet Do not display any stats.\n"
" -a, --app-stats Display application (syscall) statistics.\n"
@@ -966,7 +1138,9 @@ static void usage(const char *prog)
"\n";
fprintf(stderr, str, prog, XSK_UMEM__DEFAULT_FRAME_SIZE,
opt_batch_size, MIN_PKT_SIZE, MIN_PKT_SIZE,
- XSK_UMEM__DEFAULT_FRAME_SIZE, opt_pkt_fill_pattern);
+ XSK_UMEM__DEFAULT_FRAME_SIZE, opt_pkt_fill_pattern,
+ VLAN_VID__DEFAULT, VLAN_PRI__DEFAULT,
+ SCHED_PRI__DEFAULT);
exit(EXIT_FAILURE);
}
@@ -978,7 +1152,8 @@ static void parse_command_line(int argc, char **argv)
opterr = 0;
for (;;) {
- c = getopt_long(argc, argv, "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQaI:BR",
+ c = getopt_long(argc, argv,
+ "Frtli:q:pSNn:w:O:czf:muMd:b:C:s:P:VJ:K:G:H:T:yW:U:xQaI:BR",
long_options, &option_index);
if (c == -1)
break;
@@ -1012,6 +1187,17 @@ static void parse_command_line(int argc, char **argv)
case 'n':
opt_interval = atoi(optarg);
break;
+ case 'w':
+ if (get_clockid(&opt_clock, optarg)) {
+ fprintf(stderr,
+ "ERROR: Invalid clock %s. Default to CLOCK_MONOTONIC.\n",
+ optarg);
+ opt_clock = CLOCK_MONOTONIC;
+ }
+ break;
+ case 'O':
+ opt_retries = atoi(optarg);
+ break;
case 'z':
opt_xdp_bind_flags |= XDP_ZEROCOPY;
break;
@@ -1059,6 +1245,49 @@ static void parse_command_line(int argc, char **argv)
case 'P':
opt_pkt_fill_pattern = strtol(optarg, NULL, 16);
break;
+ case 'V':
+ opt_vlan_tag = true;
+ break;
+ case 'J':
+ opt_pkt_vlan_id = atoi(optarg);
+ break;
+ case 'K':
+ opt_pkt_vlan_pri = atoi(optarg);
+ break;
+ case 'G':
+ if (!ether_aton_r(optarg,
+ (struct ether_addr *)&opt_txdmac)) {
+ fprintf(stderr, "Invalid dmac address:%s\n",
+ optarg);
+ usage(basename(argv[0]));
+ }
+ break;
+ case 'H':
+ if (!ether_aton_r(optarg,
+ (struct ether_addr *)&opt_txsmac)) {
+ fprintf(stderr, "Invalid smac address:%s\n",
+ optarg);
+ usage(basename(argv[0]));
+ }
+ break;
+ case 'T':
+ opt_tx_cycle_ns = atoi(optarg);
+ opt_tx_cycle_ns *= NSEC_PER_USEC;
+ break;
+ case 'y':
+ opt_tstamp = 1;
+ break;
+ case 'W':
+ if (get_schpolicy(&opt_schpolicy, optarg)) {
+ fprintf(stderr,
+ "ERROR: Invalid policy %s. Default to SCHED_OTHER.\n",
+ optarg);
+ opt_schpolicy = SCHED_OTHER;
+ }
+ break;
+ case 'U':
+ opt_schprio = atoi(optarg);
+ break;
case 'x':
opt_extra_stats = 1;
break;
@@ -1264,16 +1493,22 @@ static void rx_drop_all(void)
}
}
-static void tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size)
+static int tx_only(struct xsk_socket_info *xsk, u32 *frame_nb,
+ int batch_size, unsigned long tx_ns)
{
- u32 idx;
+ u32 idx, tv_sec, tv_usec;
unsigned int i;
while (xsk_ring_prod__reserve(&xsk->tx, batch_size, &idx) <
batch_size) {
complete_tx_only(xsk, batch_size);
if (benchmark_done)
- return;
+ return 0;
+ }
+
+ if (opt_tstamp) {
+ tv_sec = (u32)(tx_ns / NSEC_PER_SEC);
+ tv_usec = (u32)((tx_ns % NSEC_PER_SEC) / 1000);
}
for (i = 0; i < batch_size; i++) {
@@ -1281,6 +1516,21 @@ static void tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size)
idx + i);
tx_desc->addr = (*frame_nb + i) * opt_xsk_frame_size;
tx_desc->len = PKT_SIZE;
+
+ if (opt_tstamp) {
+ struct pktgen_hdr *pktgen_hdr;
+ u64 addr = tx_desc->addr;
+ char *pkt;
+
+ pkt = xsk_umem__get_data(xsk->umem->buffer, addr);
+ pktgen_hdr = (struct pktgen_hdr *)(pkt + PKTGEN_HDR_OFFSET);
+
+ pktgen_hdr->seq_num = htonl(sequence++);
+ pktgen_hdr->tv_sec = htonl(tv_sec);
+ pktgen_hdr->tv_usec = htonl(tv_usec);
+
+ hex_dump(pkt, PKT_SIZE, addr);
+ }
}
xsk_ring_prod__submit(&xsk->tx, batch_size);
@@ -1289,6 +1539,8 @@ static void tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size)
*frame_nb += batch_size;
*frame_nb %= NUM_FRAMES;
complete_tx_only(xsk, batch_size);
+
+ return batch_size;
}
static inline int get_batch_size(int pkt_cnt)
@@ -1315,23 +1567,48 @@ static void complete_tx_only_all(void)
pending = !!xsks[i]->outstanding_tx;
}
}
- } while (pending);
+ sleep(1);
+ } while (pending && opt_retries-- > 0);
}
static void tx_only_all(void)
{
struct pollfd fds[MAX_SOCKS] = {};
u32 frame_nb[MAX_SOCKS] = {};
+ unsigned long next_tx_ns = 0;
int pkt_cnt = 0;
int i, ret;
+ if (opt_poll && opt_tx_cycle_ns) {
+ fprintf(stderr,
+ "Error: --poll and --tx-cycles are both set\n");
+ return;
+ }
+
for (i = 0; i < num_socks; i++) {
fds[0].fd = xsk_socket__fd(xsks[i]->xsk);
fds[0].events = POLLOUT;
}
+ if (opt_tx_cycle_ns) {
+ /* Align Tx time to micro-second boundary */
+ next_tx_ns = (get_nsecs() / NSEC_PER_USEC + 1) *
+ NSEC_PER_USEC;
+ next_tx_ns += opt_tx_cycle_ns;
+
+ /* Initialize periodic Tx scheduling variance */
+ tx_cycle_diff_min = 1000000000;
+ tx_cycle_diff_max = 0;
+ tx_cycle_diff_ave = 0.0;
+ }
+
while ((opt_pkt_count && pkt_cnt < opt_pkt_count) || !opt_pkt_count) {
int batch_size = get_batch_size(pkt_cnt);
+ unsigned long tx_ns = 0;
+ struct timespec next;
+ int tx_cnt = 0;
+ long diff;
+ int err;
if (opt_poll) {
for (i = 0; i < num_socks; i++)
@@ -1344,13 +1621,43 @@ static void tx_only_all(void)
continue;
}
+ if (opt_tx_cycle_ns) {
+ next.tv_sec = next_tx_ns / NSEC_PER_SEC;
+ next.tv_nsec = next_tx_ns % NSEC_PER_SEC;
+ err = clock_nanosleep(opt_clock, TIMER_ABSTIME, &next, NULL);
+ if (err) {
+ if (err != EINTR)
+ fprintf(stderr,
+ "clock_nanosleep failed. Err:%d errno:%d\n",
+ err, errno);
+ break;
+ }
+
+ /* Measure periodic Tx scheduling variance */
+ tx_ns = get_nsecs();
+ diff = tx_ns - next_tx_ns;
+ if (diff < tx_cycle_diff_min)
+ tx_cycle_diff_min = diff;
+
+ if (diff > tx_cycle_diff_max)
+ tx_cycle_diff_max = diff;
+
+ tx_cycle_diff_ave += (double)diff;
+ tx_cycle_cnt++;
+ } else if (opt_tstamp) {
+ tx_ns = get_nsecs();
+ }
+
for (i = 0; i < num_socks; i++)
- tx_only(xsks[i], &frame_nb[i], batch_size);
+ tx_cnt += tx_only(xsks[i], &frame_nb[i], batch_size, tx_ns);
- pkt_cnt += batch_size;
+ pkt_cnt += tx_cnt;
if (benchmark_done)
break;
+
+ if (opt_tx_cycle_ns)
+ next_tx_ns += opt_tx_cycle_ns;
}
if (opt_pkt_count)
@@ -1581,6 +1888,7 @@ int main(int argc, char **argv)
struct __user_cap_data_struct data[2] = { { 0 } };
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
bool rx = false, tx = false;
+ struct sched_param schparam;
struct xsk_umem_info *umem;
struct bpf_object *obj;
int xsks_map_fd = 0;
@@ -1643,6 +1951,9 @@ int main(int argc, char **argv)
apply_setsockopt(xsks[i]);
if (opt_bench == BENCH_TXONLY) {
+ if (opt_tstamp && opt_pkt_size < PKTGEN_SIZE_MIN)
+ opt_pkt_size = PKTGEN_SIZE_MIN;
+
gen_eth_hdr_data();
for (i = 0; i < NUM_FRAMES; i++)
@@ -1682,6 +1993,16 @@ int main(int argc, char **argv)
prev_time = get_nsecs();
start_time = prev_time;
+ /* Configure sched priority for better wake-up accuracy */
+ memset(&schparam, 0, sizeof(schparam));
+ schparam.sched_priority = opt_schprio;
+ ret = sched_setscheduler(0, opt_schpolicy, &schparam);
+ if (ret) {
+ fprintf(stderr, "Error(%d) in setting priority(%d): %s\n",
+ errno, opt_schprio, strerror(errno));
+ goto out;
+ }
+
if (opt_bench == BENCH_RXDROP)
rx_drop_all();
else if (opt_bench == BENCH_TXONLY)
@@ -1689,6 +2010,7 @@ int main(int argc, char **argv)
else
l2fwd_all();
+out:
benchmark_done = true;
if (!opt_quiet)