@@ -111,6 +111,7 @@ static bool opt_app_stats;
111111static const char * opt_irq_str = "" ;
112112static u32 irq_no ;
113113static int irqs_at_init = -1 ;
114+ static u32 sequence ;
114115static int opt_poll ;
115116static int opt_interval = 1 ;
116117static int opt_retries = 3 ;
@@ -129,6 +130,7 @@ static clockid_t opt_clock = CLOCK_MONOTONIC;
129130static unsigned long opt_tx_cycle_ns ;
130131static int opt_schpolicy = SCHED_OTHER ;
131132static int opt_schprio = SCHED_PRI__DEFAULT ;
133+ static bool opt_tstamp ;
132134
133135struct 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+
141151struct 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
847863static u8 pkt_data [XSK_UMEM__DEFAULT_FRAME_SIZE ];
848864
849865static 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