Skip to content

Commit eb68db4

Browse files
elvinongblAlexei Starovoitov
authored and
Alexei Starovoitov
committed
samples/bpf: xdpsock: Add timestamp for Tx-only operation
It may be useful to add timestamp for Tx packets for continuous or cyclic transmit operation. The timestamp and sequence ID of a Tx packet are stored according to pktgen header format. To enable per-packet timestamp, use -y|--tstamp option. If timestamp is off, pktgen header is not included in the UDP payload. This means receiving side can use the magic number for pktgen for differentiation. The implementation supports both VLAN tagged and untagged option. By default, the minimum packet size is set at 64B. However, if VLAN tagged is on (-V), the minimum packet size is increased to 66B just so to fit the pktgen_hdr size. Added hex_dump() into the code path just for future cross-checking. As before, simply change to "#define DEBUG_HEXDUMP 1" to inspect the accuracy of TX packet. Signed-off-by: Ong Boon Leong <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 8121e78 commit eb68db4

File tree

1 file changed

+68
-9
lines changed

1 file changed

+68
-9
lines changed

samples/bpf/xdpsock_user.c

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static bool opt_app_stats;
111111
static const char *opt_irq_str = "";
112112
static u32 irq_no;
113113
static int irqs_at_init = -1;
114+
static u32 sequence;
114115
static int opt_poll;
115116
static int opt_interval = 1;
116117
static int opt_retries = 3;
@@ -129,6 +130,7 @@ static clockid_t opt_clock = CLOCK_MONOTONIC;
129130
static unsigned long opt_tx_cycle_ns;
130131
static int opt_schpolicy = SCHED_OTHER;
131132
static int opt_schprio = SCHED_PRI__DEFAULT;
133+
static bool opt_tstamp;
132134

133135
struct vlan_ethhdr {
134136
unsigned char h_dest[6];
@@ -138,6 +140,14 @@ struct vlan_ethhdr {
138140
__be16 h_vlan_encapsulated_proto;
139141
};
140142

143+
#define PKTGEN_MAGIC 0xbe9be955
144+
struct pktgen_hdr {
145+
__be32 pgh_magic;
146+
__be32 seq_num;
147+
__be32 tv_sec;
148+
__be32 tv_usec;
149+
};
150+
141151
struct xsk_ring_stats {
142152
unsigned long rx_npkts;
143153
unsigned long tx_npkts;
@@ -836,18 +846,25 @@ static inline u16 udp_csum(u32 saddr, u32 daddr, u32 len,
836846

837847
#define ETH_HDR_SIZE (opt_vlan_tag ? sizeof(struct vlan_ethhdr) : \
838848
sizeof(struct ethhdr))
849+
#define PKTGEN_HDR_SIZE (opt_tstamp ? sizeof(struct pktgen_hdr) : 0)
839850
#define PKT_HDR_SIZE (ETH_HDR_SIZE + sizeof(struct iphdr) + \
840-
sizeof(struct udphdr))
851+
sizeof(struct udphdr) + PKTGEN_HDR_SIZE)
852+
#define PKTGEN_HDR_OFFSET (ETH_HDR_SIZE + sizeof(struct iphdr) + \
853+
sizeof(struct udphdr))
854+
#define PKTGEN_SIZE_MIN (PKTGEN_HDR_OFFSET + sizeof(struct pktgen_hdr) + \
855+
ETH_FCS_SIZE)
841856

842857
#define PKT_SIZE (opt_pkt_size - ETH_FCS_SIZE)
843858
#define IP_PKT_SIZE (PKT_SIZE - ETH_HDR_SIZE)
844859
#define UDP_PKT_SIZE (IP_PKT_SIZE - sizeof(struct iphdr))
845-
#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - sizeof(struct udphdr))
860+
#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - \
861+
(sizeof(struct udphdr) + PKTGEN_HDR_SIZE))
846862

847863
static u8 pkt_data[XSK_UMEM__DEFAULT_FRAME_SIZE];
848864

849865
static void gen_eth_hdr_data(void)
850866
{
867+
struct pktgen_hdr *pktgen_hdr;
851868
struct udphdr *udp_hdr;
852869
struct iphdr *ip_hdr;
853870

@@ -860,7 +877,10 @@ static void gen_eth_hdr_data(void)
860877
sizeof(struct iphdr));
861878
ip_hdr = (struct iphdr *)(pkt_data +
862879
sizeof(struct vlan_ethhdr));
863-
880+
pktgen_hdr = (struct pktgen_hdr *)(pkt_data +
881+
sizeof(struct vlan_ethhdr) +
882+
sizeof(struct iphdr) +
883+
sizeof(struct udphdr));
864884
/* ethernet & VLAN header */
865885
memcpy(veth_hdr->h_dest, &opt_txdmac, ETH_ALEN);
866886
memcpy(veth_hdr->h_source, &opt_txsmac, ETH_ALEN);
@@ -877,7 +897,10 @@ static void gen_eth_hdr_data(void)
877897
sizeof(struct iphdr));
878898
ip_hdr = (struct iphdr *)(pkt_data +
879899
sizeof(struct ethhdr));
880-
900+
pktgen_hdr = (struct pktgen_hdr *)(pkt_data +
901+
sizeof(struct ethhdr) +
902+
sizeof(struct iphdr) +
903+
sizeof(struct udphdr));
881904
/* ethernet header */
882905
memcpy(eth_hdr->h_dest, &opt_txdmac, ETH_ALEN);
883906
memcpy(eth_hdr->h_source, &opt_txsmac, ETH_ALEN);
@@ -906,6 +929,9 @@ static void gen_eth_hdr_data(void)
906929
udp_hdr->dest = htons(0x1000);
907930
udp_hdr->len = htons(UDP_PKT_SIZE);
908931

932+
if (opt_tstamp)
933+
pktgen_hdr->pgh_magic = htonl(PKTGEN_MAGIC);
934+
909935
/* UDP data */
910936
memset32_htonl(pkt_data + PKT_HDR_SIZE, opt_pkt_fill_pattern,
911937
UDP_PKT_DATA_SIZE);
@@ -1049,6 +1075,7 @@ static struct option long_options[] = {
10491075
{"tx-dmac", required_argument, 0, 'G'},
10501076
{"tx-smac", required_argument, 0, 'H'},
10511077
{"tx-cycle", required_argument, 0, 'T'},
1078+
{"tstamp", no_argument, 0, 'y'},
10521079
{"policy", required_argument, 0, 'W'},
10531080
{"schpri", required_argument, 0, 'U'},
10541081
{"extra-stats", no_argument, 0, 'x'},
@@ -1099,6 +1126,7 @@ static void usage(const char *prog)
10991126
" -G, --tx-dmac=<MAC> Dest MAC addr of TX frame in aa:bb:cc:dd:ee:ff format (For -V|--tx-vlan)\n"
11001127
" -H, --tx-smac=<MAC> Src MAC addr of TX frame in aa:bb:cc:dd:ee:ff format (For -V|--tx-vlan)\n"
11011128
" -T, --tx-cycle=n Tx cycle time in micro-seconds (For -t|--txonly).\n"
1129+
" -y, --tstamp Add time-stamp to packet (For -t|--txonly).\n"
11021130
" -W, --policy=POLICY Schedule policy. Default: SCHED_OTHER\n"
11031131
" -U, --schpri=n Schedule priority. Default: %d\n"
11041132
" -x, --extra-stats Display extra statistics.\n"
@@ -1125,7 +1153,7 @@ static void parse_command_line(int argc, char **argv)
11251153

11261154
for (;;) {
11271155
c = getopt_long(argc, argv,
1128-
"Frtli:q:pSNn:w:O:czf:muMd:b:C:s:P:VJ:K:G:H:T:W:U:xQaI:BR",
1156+
"Frtli:q:pSNn:w:O:czf:muMd:b:C:s:P:VJ:K:G:H:T:yW:U:xQaI:BR",
11291157
long_options, &option_index);
11301158
if (c == -1)
11311159
break;
@@ -1246,6 +1274,9 @@ static void parse_command_line(int argc, char **argv)
12461274
opt_tx_cycle_ns = atoi(optarg);
12471275
opt_tx_cycle_ns *= NSEC_PER_USEC;
12481276
break;
1277+
case 'y':
1278+
opt_tstamp = 1;
1279+
break;
12491280
case 'W':
12501281
if (get_schpolicy(&opt_schpolicy, optarg)) {
12511282
fprintf(stderr,
@@ -1462,9 +1493,10 @@ static void rx_drop_all(void)
14621493
}
14631494
}
14641495

1465-
static int tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size)
1496+
static int tx_only(struct xsk_socket_info *xsk, u32 *frame_nb,
1497+
int batch_size, unsigned long tx_ns)
14661498
{
1467-
u32 idx;
1499+
u32 idx, tv_sec, tv_usec;
14681500
unsigned int i;
14691501

14701502
while (xsk_ring_prod__reserve(&xsk->tx, batch_size, &idx) <
@@ -1474,11 +1506,31 @@ static int tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size)
14741506
return 0;
14751507
}
14761508

1509+
if (opt_tstamp) {
1510+
tv_sec = (u32)(tx_ns / NSEC_PER_SEC);
1511+
tv_usec = (u32)((tx_ns % NSEC_PER_SEC) / 1000);
1512+
}
1513+
14771514
for (i = 0; i < batch_size; i++) {
14781515
struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx,
14791516
idx + i);
14801517
tx_desc->addr = (*frame_nb + i) * opt_xsk_frame_size;
14811518
tx_desc->len = PKT_SIZE;
1519+
1520+
if (opt_tstamp) {
1521+
struct pktgen_hdr *pktgen_hdr;
1522+
u64 addr = tx_desc->addr;
1523+
char *pkt;
1524+
1525+
pkt = xsk_umem__get_data(xsk->umem->buffer, addr);
1526+
pktgen_hdr = (struct pktgen_hdr *)(pkt + PKTGEN_HDR_OFFSET);
1527+
1528+
pktgen_hdr->seq_num = htonl(sequence++);
1529+
pktgen_hdr->tv_sec = htonl(tv_sec);
1530+
pktgen_hdr->tv_usec = htonl(tv_usec);
1531+
1532+
hex_dump(pkt, PKT_SIZE, addr);
1533+
}
14821534
}
14831535

14841536
xsk_ring_prod__submit(&xsk->tx, batch_size);
@@ -1552,6 +1604,7 @@ static void tx_only_all(void)
15521604

15531605
while ((opt_pkt_count && pkt_cnt < opt_pkt_count) || !opt_pkt_count) {
15541606
int batch_size = get_batch_size(pkt_cnt);
1607+
unsigned long tx_ns = 0;
15551608
struct timespec next;
15561609
int tx_cnt = 0;
15571610
long diff;
@@ -1581,7 +1634,8 @@ static void tx_only_all(void)
15811634
}
15821635

15831636
/* Measure periodic Tx scheduling variance */
1584-
diff = get_nsecs() - next_tx_ns;
1637+
tx_ns = get_nsecs();
1638+
diff = tx_ns - next_tx_ns;
15851639
if (diff < tx_cycle_diff_min)
15861640
tx_cycle_diff_min = diff;
15871641

@@ -1590,10 +1644,12 @@ static void tx_only_all(void)
15901644

15911645
tx_cycle_diff_ave += (double)diff;
15921646
tx_cycle_cnt++;
1647+
} else if (opt_tstamp) {
1648+
tx_ns = get_nsecs();
15931649
}
15941650

15951651
for (i = 0; i < num_socks; i++)
1596-
tx_cnt += tx_only(xsks[i], &frame_nb[i], batch_size);
1652+
tx_cnt += tx_only(xsks[i], &frame_nb[i], batch_size, tx_ns);
15971653

15981654
pkt_cnt += tx_cnt;
15991655

@@ -1895,6 +1951,9 @@ int main(int argc, char **argv)
18951951
apply_setsockopt(xsks[i]);
18961952

18971953
if (opt_bench == BENCH_TXONLY) {
1954+
if (opt_tstamp && opt_pkt_size < PKTGEN_SIZE_MIN)
1955+
opt_pkt_size = PKTGEN_SIZE_MIN;
1956+
18981957
gen_eth_hdr_data();
18991958

19001959
for (i = 0; i < NUM_FRAMES; i++)

0 commit comments

Comments
 (0)