xref: /dpdk/examples/ptpclient/ptpclient.c (revision 7f2a987ca852a45bdb4520edc7ad7e02c4efd269)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson  * Copyright(c) 2015 Intel Corporation
3ab129e90SDaniel Mrzyglod  */
4ab129e90SDaniel Mrzyglod 
5ab129e90SDaniel Mrzyglod /*
6ab129e90SDaniel Mrzyglod  * This application is a simple Layer 2 PTP v2 client. It shows delta values
7ab129e90SDaniel Mrzyglod  * which are used to synchronize the PHC clock. if the "-T 1" parameter is
8ab129e90SDaniel Mrzyglod  * passed to the application the Linux kernel clock is also synchronized.
9ab129e90SDaniel Mrzyglod  */
10ab129e90SDaniel Mrzyglod 
11ab129e90SDaniel Mrzyglod #include <stdint.h>
1272b452c5SDmitry Kozlyuk #include <stdlib.h>
13ab129e90SDaniel Mrzyglod #include <inttypes.h>
14ab129e90SDaniel Mrzyglod #include <rte_eal.h>
15ab129e90SDaniel Mrzyglod #include <rte_ethdev.h>
16ab129e90SDaniel Mrzyglod #include <rte_cycles.h>
17ab129e90SDaniel Mrzyglod #include <rte_lcore.h>
18ab129e90SDaniel Mrzyglod #include <rte_mbuf.h>
19ab129e90SDaniel Mrzyglod #include <rte_ip.h>
20ab129e90SDaniel Mrzyglod #include <limits.h>
21ab129e90SDaniel Mrzyglod #include <sys/time.h>
22ab129e90SDaniel Mrzyglod #include <getopt.h>
238badf48dSRahul Bhansali #include <signal.h>
248badf48dSRahul Bhansali 
258badf48dSRahul Bhansali static volatile bool force_quit;
26ab129e90SDaniel Mrzyglod 
27867a6c66SKevin Laatz #define RX_RING_SIZE 1024
28867a6c66SKevin Laatz #define TX_RING_SIZE 1024
29ab129e90SDaniel Mrzyglod 
30ab129e90SDaniel Mrzyglod #define NUM_MBUFS            8191
31ab129e90SDaniel Mrzyglod #define MBUF_CACHE_SIZE       250
32ab129e90SDaniel Mrzyglod 
33ab129e90SDaniel Mrzyglod /* Values for the PTP messageType field. */
34ab129e90SDaniel Mrzyglod #define SYNC                  0x0
35ab129e90SDaniel Mrzyglod #define DELAY_REQ             0x1
36ab129e90SDaniel Mrzyglod #define PDELAY_REQ            0x2
37ab129e90SDaniel Mrzyglod #define PDELAY_RESP           0x3
38ab129e90SDaniel Mrzyglod #define FOLLOW_UP             0x8
39ab129e90SDaniel Mrzyglod #define DELAY_RESP            0x9
40ab129e90SDaniel Mrzyglod #define PDELAY_RESP_FOLLOW_UP 0xA
41ab129e90SDaniel Mrzyglod #define ANNOUNCE              0xB
42ab129e90SDaniel Mrzyglod #define SIGNALING             0xC
43ab129e90SDaniel Mrzyglod #define MANAGEMENT            0xD
44ab129e90SDaniel Mrzyglod 
45ab129e90SDaniel Mrzyglod #define NSEC_PER_SEC        1000000000L
46ab129e90SDaniel Mrzyglod #define KERNEL_TIME_ADJUST_LIMIT  20000
47ab129e90SDaniel Mrzyglod #define PTP_PROTOCOL             0x88F7
48ab129e90SDaniel Mrzyglod 
49ab129e90SDaniel Mrzyglod struct rte_mempool *mbuf_pool;
50ab129e90SDaniel Mrzyglod uint32_t ptp_enabled_port_mask;
51ab129e90SDaniel Mrzyglod uint8_t ptp_enabled_port_nb;
52ab129e90SDaniel Mrzyglod static uint8_t ptp_enabled_ports[RTE_MAX_ETHPORTS];
53ab129e90SDaniel Mrzyglod 
546d13ea8eSOlivier Matz static const struct rte_ether_addr ether_multicast = {
55ab129e90SDaniel Mrzyglod 	.addr_bytes = {0x01, 0x1b, 0x19, 0x0, 0x0, 0x0}
56ab129e90SDaniel Mrzyglod };
57ab129e90SDaniel Mrzyglod 
58ab129e90SDaniel Mrzyglod /* Structs used for PTP handling. */
59*7f2a987cSAndre Muezerie struct __rte_packed_begin tstamp {
60ab129e90SDaniel Mrzyglod 	uint16_t   sec_msb;
61ab129e90SDaniel Mrzyglod 	uint32_t   sec_lsb;
62ab129e90SDaniel Mrzyglod 	uint32_t   ns;
63*7f2a987cSAndre Muezerie } __rte_packed_end;
64ab129e90SDaniel Mrzyglod 
65ab129e90SDaniel Mrzyglod struct clock_id {
66ab129e90SDaniel Mrzyglod 	uint8_t id[8];
67ab129e90SDaniel Mrzyglod };
68ab129e90SDaniel Mrzyglod 
69*7f2a987cSAndre Muezerie struct __rte_packed_begin port_id {
70ab129e90SDaniel Mrzyglod 	struct clock_id        clock_id;
71ab129e90SDaniel Mrzyglod 	uint16_t               port_number;
72*7f2a987cSAndre Muezerie } __rte_packed_end;
73ab129e90SDaniel Mrzyglod 
74*7f2a987cSAndre Muezerie struct __rte_packed_begin ptp_header {
75ab129e90SDaniel Mrzyglod 	uint8_t              msg_type;
76ab129e90SDaniel Mrzyglod 	uint8_t              ver;
77ab129e90SDaniel Mrzyglod 	uint16_t             message_length;
78ab129e90SDaniel Mrzyglod 	uint8_t              domain_number;
79ab129e90SDaniel Mrzyglod 	uint8_t              reserved1;
80ab129e90SDaniel Mrzyglod 	uint8_t              flag_field[2];
81ab129e90SDaniel Mrzyglod 	int64_t              correction;
82ab129e90SDaniel Mrzyglod 	uint32_t             reserved2;
83ab129e90SDaniel Mrzyglod 	struct port_id       source_port_id;
84ab129e90SDaniel Mrzyglod 	uint16_t             seq_id;
85ab129e90SDaniel Mrzyglod 	uint8_t              control;
86ab129e90SDaniel Mrzyglod 	int8_t               log_message_interval;
87*7f2a987cSAndre Muezerie } __rte_packed_end;
88ab129e90SDaniel Mrzyglod 
89*7f2a987cSAndre Muezerie struct __rte_packed_begin sync_msg {
90ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
91ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
92*7f2a987cSAndre Muezerie } __rte_packed_end;
93ab129e90SDaniel Mrzyglod 
94*7f2a987cSAndre Muezerie struct __rte_packed_begin follow_up_msg {
95ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
96ab129e90SDaniel Mrzyglod 	struct tstamp       precise_origin_tstamp;
97013b4c52SBruce Richardson 	uint8_t             suffix[];
98*7f2a987cSAndre Muezerie } __rte_packed_end;
99ab129e90SDaniel Mrzyglod 
100*7f2a987cSAndre Muezerie struct __rte_packed_begin delay_req_msg {
101ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
102ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
103*7f2a987cSAndre Muezerie } __rte_packed_end;
104ab129e90SDaniel Mrzyglod 
105*7f2a987cSAndre Muezerie struct __rte_packed_begin delay_resp_msg {
106ab129e90SDaniel Mrzyglod 	struct ptp_header    hdr;
107ab129e90SDaniel Mrzyglod 	struct tstamp        rx_tstamp;
108ab129e90SDaniel Mrzyglod 	struct port_id       req_port_id;
109013b4c52SBruce Richardson 	uint8_t              suffix[];
110*7f2a987cSAndre Muezerie } __rte_packed_end;
111ab129e90SDaniel Mrzyglod 
112ab129e90SDaniel Mrzyglod struct ptp_message {
113*7f2a987cSAndre Muezerie 	union __rte_packed_begin {
114ab129e90SDaniel Mrzyglod 		struct ptp_header          header;
115ab129e90SDaniel Mrzyglod 		struct sync_msg            sync;
116ab129e90SDaniel Mrzyglod 		struct delay_req_msg       delay_req;
117ab129e90SDaniel Mrzyglod 		struct follow_up_msg       follow_up;
118ab129e90SDaniel Mrzyglod 		struct delay_resp_msg      delay_resp;
119*7f2a987cSAndre Muezerie 	} __rte_packed_end;
120ab129e90SDaniel Mrzyglod };
121ab129e90SDaniel Mrzyglod 
122b8d1d60fSStephen Hemminger struct ptpv2_time_receiver_ordinary {
123ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
124ab129e90SDaniel Mrzyglod 	struct timespec tstamp1;
125ab129e90SDaniel Mrzyglod 	struct timespec tstamp2;
126ab129e90SDaniel Mrzyglod 	struct timespec tstamp3;
127ab129e90SDaniel Mrzyglod 	struct timespec tstamp4;
128ab129e90SDaniel Mrzyglod 	struct clock_id client_clock_id;
129b8d1d60fSStephen Hemminger 	struct clock_id transmitter_clock_id;
130ab129e90SDaniel Mrzyglod 	struct timeval new_adj;
131ab129e90SDaniel Mrzyglod 	int64_t delta;
132f8244c63SZhiyong Yang 	uint16_t portid;
133ab129e90SDaniel Mrzyglod 	uint16_t seqID_SYNC;
134ab129e90SDaniel Mrzyglod 	uint16_t seqID_FOLLOWUP;
135ab129e90SDaniel Mrzyglod 	uint8_t ptpset;
136ab129e90SDaniel Mrzyglod 	uint8_t kernel_time_set;
137f8244c63SZhiyong Yang 	uint16_t current_ptp_port;
138ab129e90SDaniel Mrzyglod };
139ab129e90SDaniel Mrzyglod 
140b8d1d60fSStephen Hemminger static struct ptpv2_time_receiver_ordinary ptp_data;
141ab129e90SDaniel Mrzyglod 
142ab129e90SDaniel Mrzyglod static inline uint64_t timespec64_to_ns(const struct timespec *ts)
143ab129e90SDaniel Mrzyglod {
144ab129e90SDaniel Mrzyglod 	return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
145ab129e90SDaniel Mrzyglod }
146ab129e90SDaniel Mrzyglod 
147ab129e90SDaniel Mrzyglod static struct timeval
148ab129e90SDaniel Mrzyglod ns_to_timeval(int64_t nsec)
149ab129e90SDaniel Mrzyglod {
150ab129e90SDaniel Mrzyglod 	struct timespec t_spec = {0, 0};
151ab129e90SDaniel Mrzyglod 	struct timeval t_eval = {0, 0};
152ab129e90SDaniel Mrzyglod 	int32_t rem;
153ab129e90SDaniel Mrzyglod 
154ab129e90SDaniel Mrzyglod 	if (nsec == 0)
155ab129e90SDaniel Mrzyglod 		return t_eval;
156ab129e90SDaniel Mrzyglod 	rem = nsec % NSEC_PER_SEC;
157ab129e90SDaniel Mrzyglod 	t_spec.tv_sec = nsec / NSEC_PER_SEC;
158ab129e90SDaniel Mrzyglod 
159ab129e90SDaniel Mrzyglod 	if (rem < 0) {
160ab129e90SDaniel Mrzyglod 		t_spec.tv_sec--;
161ab129e90SDaniel Mrzyglod 		rem += NSEC_PER_SEC;
162ab129e90SDaniel Mrzyglod 	}
163ab129e90SDaniel Mrzyglod 
164ab129e90SDaniel Mrzyglod 	t_spec.tv_nsec = rem;
165ab129e90SDaniel Mrzyglod 	t_eval.tv_sec = t_spec.tv_sec;
166ab129e90SDaniel Mrzyglod 	t_eval.tv_usec = t_spec.tv_nsec / 1000;
167ab129e90SDaniel Mrzyglod 
168ab129e90SDaniel Mrzyglod 	return t_eval;
169ab129e90SDaniel Mrzyglod }
170ab129e90SDaniel Mrzyglod 
171ab129e90SDaniel Mrzyglod /*
172ab129e90SDaniel Mrzyglod  * Initializes a given port using global settings and with the RX buffers
173ab129e90SDaniel Mrzyglod  * coming from the mbuf_pool passed as a parameter.
174ab129e90SDaniel Mrzyglod  */
175ab129e90SDaniel Mrzyglod static inline int
17647523597SZhiyong Yang port_init(uint16_t port, struct rte_mempool *mbuf_pool)
177ab129e90SDaniel Mrzyglod {
178ab129e90SDaniel Mrzyglod 	struct rte_eth_dev_info dev_info;
1791bb4a528SFerruh Yigit 	struct rte_eth_conf port_conf;
180ab129e90SDaniel Mrzyglod 	const uint16_t rx_rings = 1;
181ab129e90SDaniel Mrzyglod 	const uint16_t tx_rings = 1;
182ab129e90SDaniel Mrzyglod 	int retval;
183ab129e90SDaniel Mrzyglod 	uint16_t q;
18460efb44fSRoman Zhukov 	uint16_t nb_rxd = RX_RING_SIZE;
18560efb44fSRoman Zhukov 	uint16_t nb_txd = TX_RING_SIZE;
186ab129e90SDaniel Mrzyglod 
187a9dbe180SThomas Monjalon 	if (!rte_eth_dev_is_valid_port(port))
188ab129e90SDaniel Mrzyglod 		return -1;
189ab129e90SDaniel Mrzyglod 
1901bb4a528SFerruh Yigit 	memset(&port_conf, 0, sizeof(struct rte_eth_conf));
1911bb4a528SFerruh Yigit 
192089e5ed7SIvan Ilchenko 	retval = rte_eth_dev_info_get(port, &dev_info);
193089e5ed7SIvan Ilchenko 	if (retval != 0) {
194089e5ed7SIvan Ilchenko 		printf("Error during getting device (port %u) info: %s\n",
195089e5ed7SIvan Ilchenko 				port, strerror(-retval));
196089e5ed7SIvan Ilchenko 
197089e5ed7SIvan Ilchenko 		return retval;
198089e5ed7SIvan Ilchenko 	}
199089e5ed7SIvan Ilchenko 
200295968d1SFerruh Yigit 	if (dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP)
201295968d1SFerruh Yigit 		port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
2027a04a4f6SHemant Agrawal 
203295968d1SFerruh Yigit 	if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
204b960219bSShahaf Shuler 		port_conf.txmode.offloads |=
205295968d1SFerruh Yigit 			RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
2060625a29fSPablo de Lara 	/* Force full Tx path in the driver, required for IEEE1588 */
207295968d1SFerruh Yigit 	port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
208b960219bSShahaf Shuler 
209ab129e90SDaniel Mrzyglod 	/* Configure the Ethernet device. */
210ab129e90SDaniel Mrzyglod 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
211ab129e90SDaniel Mrzyglod 	if (retval != 0)
212ab129e90SDaniel Mrzyglod 		return retval;
213ab129e90SDaniel Mrzyglod 
21460efb44fSRoman Zhukov 	retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
21560efb44fSRoman Zhukov 	if (retval != 0)
21660efb44fSRoman Zhukov 		return retval;
21760efb44fSRoman Zhukov 
218ab129e90SDaniel Mrzyglod 	/* Allocate and set up 1 RX queue per Ethernet port. */
219ab129e90SDaniel Mrzyglod 	for (q = 0; q < rx_rings; q++) {
22092854ed2SSimei Su 		struct rte_eth_rxconf *rxconf;
22192854ed2SSimei Su 
22292854ed2SSimei Su 		rxconf = &dev_info.default_rxconf;
22392854ed2SSimei Su 		rxconf->offloads = port_conf.rxmode.offloads;
22492854ed2SSimei Su 
22560efb44fSRoman Zhukov 		retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
22692854ed2SSimei Su 				rte_eth_dev_socket_id(port), rxconf, mbuf_pool);
227ab129e90SDaniel Mrzyglod 
228ab129e90SDaniel Mrzyglod 		if (retval < 0)
229ab129e90SDaniel Mrzyglod 			return retval;
230ab129e90SDaniel Mrzyglod 	}
231ab129e90SDaniel Mrzyglod 
232ab129e90SDaniel Mrzyglod 	/* Allocate and set up 1 TX queue per Ethernet port. */
233ab129e90SDaniel Mrzyglod 	for (q = 0; q < tx_rings; q++) {
234ab129e90SDaniel Mrzyglod 		struct rte_eth_txconf *txconf;
235ab129e90SDaniel Mrzyglod 
236ab129e90SDaniel Mrzyglod 		txconf = &dev_info.default_txconf;
237b960219bSShahaf Shuler 		txconf->offloads = port_conf.txmode.offloads;
238ab129e90SDaniel Mrzyglod 
23960efb44fSRoman Zhukov 		retval = rte_eth_tx_queue_setup(port, q, nb_txd,
240ab129e90SDaniel Mrzyglod 				rte_eth_dev_socket_id(port), txconf);
241ab129e90SDaniel Mrzyglod 		if (retval < 0)
242ab129e90SDaniel Mrzyglod 			return retval;
243ab129e90SDaniel Mrzyglod 	}
244ab129e90SDaniel Mrzyglod 
245ab129e90SDaniel Mrzyglod 	/* Start the Ethernet port. */
246ab129e90SDaniel Mrzyglod 	retval = rte_eth_dev_start(port);
247ab129e90SDaniel Mrzyglod 	if (retval < 0)
248ab129e90SDaniel Mrzyglod 		return retval;
249ab129e90SDaniel Mrzyglod 
250ab129e90SDaniel Mrzyglod 	/* Enable timesync timestamping for the Ethernet device */
251376aa383SHarman Kalra 	retval = rte_eth_timesync_enable(port);
252376aa383SHarman Kalra 	if (retval < 0) {
253376aa383SHarman Kalra 		printf("Timesync enable failed: %d\n", retval);
254376aa383SHarman Kalra 		return retval;
255376aa383SHarman Kalra 	}
256ab129e90SDaniel Mrzyglod 
257ab129e90SDaniel Mrzyglod 	/* Enable RX in promiscuous mode for the Ethernet device. */
258f430bbceSIvan Ilchenko 	retval = rte_eth_promiscuous_enable(port);
259f430bbceSIvan Ilchenko 	if (retval != 0) {
260f430bbceSIvan Ilchenko 		printf("Promiscuous mode enable failed: %s\n",
261f430bbceSIvan Ilchenko 			rte_strerror(-retval));
262f430bbceSIvan Ilchenko 		return retval;
263f430bbceSIvan Ilchenko 	}
264ab129e90SDaniel Mrzyglod 
265ab129e90SDaniel Mrzyglod 	return 0;
266ab129e90SDaniel Mrzyglod }
267ab129e90SDaniel Mrzyglod 
268ab129e90SDaniel Mrzyglod static void
269b8d1d60fSStephen Hemminger print_clock_info(struct ptpv2_time_receiver_ordinary *ptp_data)
270ab129e90SDaniel Mrzyglod {
271ab129e90SDaniel Mrzyglod 	int64_t nsec;
272ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
273ab129e90SDaniel Mrzyglod 
274b8d1d60fSStephen Hemminger 	printf("time transmitter clock id: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
275b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[0],
276b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[1],
277b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[2],
278b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[3],
279b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[4],
280b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[5],
281b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[6],
282b8d1d60fSStephen Hemminger 		ptp_data->transmitter_clock_id.id[7]);
283ab129e90SDaniel Mrzyglod 
284b8d1d60fSStephen Hemminger 	printf("\nT2 - time receiver clock.  %lds %ldns",
285ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_sec),
286ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_nsec));
287ab129e90SDaniel Mrzyglod 
288b8d1d60fSStephen Hemminger 	printf("\nT1 - time transmitter clock.  %lds %ldns ",
289ab129e90SDaniel Mrzyglod 			ptp_data->tstamp1.tv_sec,
290ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp1.tv_nsec));
291ab129e90SDaniel Mrzyglod 
292b8d1d60fSStephen Hemminger 	printf("\nT3 - time receiver clock.  %lds %ldns",
293ab129e90SDaniel Mrzyglod 			ptp_data->tstamp3.tv_sec,
294ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp3.tv_nsec));
295ab129e90SDaniel Mrzyglod 
296b8d1d60fSStephen Hemminger 	printf("\nT4 - time transmitter clock.  %lds %ldns\n",
297ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec,
298ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp4.tv_nsec));
299ab129e90SDaniel Mrzyglod 
300b8d1d60fSStephen Hemminger 	printf("\nDelta between transmitter and receiver clocks:%"PRId64"ns\n",
301ab129e90SDaniel Mrzyglod 		ptp_data->delta);
302ab129e90SDaniel Mrzyglod 
303ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
3046d55af61SMingjin Ye 	rte_eth_timesync_read_time(ptp_data->current_ptp_port,
3056d55af61SMingjin Ye 					&net_time);
306ab129e90SDaniel Mrzyglod 
307ab129e90SDaniel Mrzyglod 	time_t ts = net_time.tv_sec;
308ab129e90SDaniel Mrzyglod 
309ab129e90SDaniel Mrzyglod 	printf("\n\nComparison between Linux kernel Time and PTP:");
310ab129e90SDaniel Mrzyglod 
311ab129e90SDaniel Mrzyglod 	printf("\nCurrent PTP Time: %.24s %.9ld ns",
312ab129e90SDaniel Mrzyglod 		ctime(&ts), net_time.tv_nsec);
313ab129e90SDaniel Mrzyglod 
314ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
315ab129e90SDaniel Mrzyglod 		(int64_t)timespec64_to_ns(&sys_time);
316ab129e90SDaniel Mrzyglod 	ptp_data->new_adj = ns_to_timeval(nsec);
317ab129e90SDaniel Mrzyglod 
318ab129e90SDaniel Mrzyglod 	gettimeofday(&ptp_data->new_adj, NULL);
319ab129e90SDaniel Mrzyglod 
320ab129e90SDaniel Mrzyglod 	time_t tp = ptp_data->new_adj.tv_sec;
321ab129e90SDaniel Mrzyglod 
322ab129e90SDaniel Mrzyglod 	printf("\nCurrent SYS Time: %.24s %.6ld ns",
323ab129e90SDaniel Mrzyglod 		ctime(&tp), ptp_data->new_adj.tv_usec);
324ab129e90SDaniel Mrzyglod 
325ab129e90SDaniel Mrzyglod 	printf("\nDelta between PTP and Linux Kernel time:%"PRId64"ns\n",
326ab129e90SDaniel Mrzyglod 		nsec);
327ab129e90SDaniel Mrzyglod 
328ab129e90SDaniel Mrzyglod 	printf("[Ctrl+C to quit]\n");
329ab129e90SDaniel Mrzyglod 
330ab129e90SDaniel Mrzyglod 	/* Clear screen and put cursor in column 1, row 1 */
331ab129e90SDaniel Mrzyglod 	printf("\033[2J\033[1;1H");
332ab129e90SDaniel Mrzyglod }
333ab129e90SDaniel Mrzyglod 
334ab129e90SDaniel Mrzyglod static int64_t
335b8d1d60fSStephen Hemminger delta_eval(struct ptpv2_time_receiver_ordinary *ptp_data)
336ab129e90SDaniel Mrzyglod {
337ab129e90SDaniel Mrzyglod 	int64_t delta;
338ab129e90SDaniel Mrzyglod 	uint64_t t1 = 0;
339ab129e90SDaniel Mrzyglod 	uint64_t t2 = 0;
340ab129e90SDaniel Mrzyglod 	uint64_t t3 = 0;
341ab129e90SDaniel Mrzyglod 	uint64_t t4 = 0;
342ab129e90SDaniel Mrzyglod 
343ab129e90SDaniel Mrzyglod 	t1 = timespec64_to_ns(&ptp_data->tstamp1);
344ab129e90SDaniel Mrzyglod 	t2 = timespec64_to_ns(&ptp_data->tstamp2);
345ab129e90SDaniel Mrzyglod 	t3 = timespec64_to_ns(&ptp_data->tstamp3);
346ab129e90SDaniel Mrzyglod 	t4 = timespec64_to_ns(&ptp_data->tstamp4);
347ab129e90SDaniel Mrzyglod 
348ab129e90SDaniel Mrzyglod 	delta = -((int64_t)((t2 - t1) - (t4 - t3))) / 2;
349ab129e90SDaniel Mrzyglod 
350ab129e90SDaniel Mrzyglod 	return delta;
351ab129e90SDaniel Mrzyglod }
352ab129e90SDaniel Mrzyglod 
353ab129e90SDaniel Mrzyglod /*
354ab129e90SDaniel Mrzyglod  * Parse the PTP SYNC message.
355ab129e90SDaniel Mrzyglod  */
356ab129e90SDaniel Mrzyglod static void
357b8d1d60fSStephen Hemminger parse_sync(struct ptpv2_time_receiver_ordinary *ptp_data, uint16_t rx_tstamp_idx)
358ab129e90SDaniel Mrzyglod {
359ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
360ab129e90SDaniel Mrzyglod 
361cebcefbaSStephen Hemminger 	ptp_hdr = rte_pktmbuf_mtod_offset(ptp_data->m, struct ptp_header *,
362cebcefbaSStephen Hemminger 					  sizeof(struct rte_ether_hdr));
363ab129e90SDaniel Mrzyglod 	ptp_data->seqID_SYNC = rte_be_to_cpu_16(ptp_hdr->seq_id);
364ab129e90SDaniel Mrzyglod 
365ab129e90SDaniel Mrzyglod 	if (ptp_data->ptpset == 0) {
366b8d1d60fSStephen Hemminger 		rte_memcpy(&ptp_data->transmitter_clock_id,
367ab129e90SDaniel Mrzyglod 				&ptp_hdr->source_port_id.clock_id,
368ab129e90SDaniel Mrzyglod 				sizeof(struct clock_id));
369ab129e90SDaniel Mrzyglod 		ptp_data->ptpset = 1;
370ab129e90SDaniel Mrzyglod 	}
371ab129e90SDaniel Mrzyglod 
372ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_hdr->source_port_id.clock_id,
373ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
374ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) == 0) {
375ab129e90SDaniel Mrzyglod 
376ab129e90SDaniel Mrzyglod 		if (ptp_data->ptpset == 1)
377ab129e90SDaniel Mrzyglod 			rte_eth_timesync_read_rx_timestamp(ptp_data->portid,
378ab129e90SDaniel Mrzyglod 					&ptp_data->tstamp2, rx_tstamp_idx);
379ab129e90SDaniel Mrzyglod 	}
380ab129e90SDaniel Mrzyglod 
381ab129e90SDaniel Mrzyglod }
382ab129e90SDaniel Mrzyglod 
383ab129e90SDaniel Mrzyglod /*
384cb056611SStephen Hemminger  * Parse the PTP FOLLOWUP message and send DELAY_REQ to the main clock.
385ab129e90SDaniel Mrzyglod  */
386ab129e90SDaniel Mrzyglod static void
387b8d1d60fSStephen Hemminger parse_fup(struct ptpv2_time_receiver_ordinary *ptp_data)
388ab129e90SDaniel Mrzyglod {
3896d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
39070febdcfSIgor Romanov 	struct rte_ether_addr eth_addr;
391ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
392ab129e90SDaniel Mrzyglod 	struct clock_id *client_clkid;
393ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
39421ba4d57SVanshika Shukla 	struct delay_req_msg *req_msg;
395ab129e90SDaniel Mrzyglod 	struct rte_mbuf *created_pkt;
396ab129e90SDaniel Mrzyglod 	struct tstamp *origin_tstamp;
3976d13ea8eSOlivier Matz 	struct rte_ether_addr eth_multicast = ether_multicast;
398ab129e90SDaniel Mrzyglod 	size_t pkt_size;
399ab129e90SDaniel Mrzyglod 	int wait_us;
400ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
40170febdcfSIgor Romanov 	int ret;
402ab129e90SDaniel Mrzyglod 
4036d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
404cebcefbaSStephen Hemminger 	ptp_hdr = rte_pktmbuf_mtod_offset(m, struct ptp_header *,
405cebcefbaSStephen Hemminger 					  sizeof(struct rte_ether_hdr));
406b8d1d60fSStephen Hemminger 	if (memcmp(&ptp_data->transmitter_clock_id,
407ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
408ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) != 0)
409ab129e90SDaniel Mrzyglod 		return;
410ab129e90SDaniel Mrzyglod 
411ab129e90SDaniel Mrzyglod 	ptp_data->seqID_FOLLOWUP = rte_be_to_cpu_16(ptp_hdr->seq_id);
412cebcefbaSStephen Hemminger 	ptp_msg = rte_pktmbuf_mtod_offset(m, struct ptp_message *,
4136d13ea8eSOlivier Matz 					  sizeof(struct rte_ether_hdr));
414ab129e90SDaniel Mrzyglod 
415ab129e90SDaniel Mrzyglod 	origin_tstamp = &ptp_msg->follow_up.precise_origin_tstamp;
416ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_nsec = ntohl(origin_tstamp->ns);
417ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_sec =
418ab129e90SDaniel Mrzyglod 		((uint64_t)ntohl(origin_tstamp->sec_lsb)) |
419ab129e90SDaniel Mrzyglod 		(((uint64_t)ntohs(origin_tstamp->sec_msb)) << 32);
420ab129e90SDaniel Mrzyglod 
421ab129e90SDaniel Mrzyglod 	if (ptp_data->seqID_FOLLOWUP == ptp_data->seqID_SYNC) {
42270febdcfSIgor Romanov 		ret = rte_eth_macaddr_get(ptp_data->portid, &eth_addr);
42370febdcfSIgor Romanov 		if (ret != 0) {
42470febdcfSIgor Romanov 			printf("\nCore %u: port %u failed to get MAC address: %s\n",
42570febdcfSIgor Romanov 				rte_lcore_id(), ptp_data->portid,
42670febdcfSIgor Romanov 				rte_strerror(-ret));
42770febdcfSIgor Romanov 			return;
42870febdcfSIgor Romanov 		}
429ab129e90SDaniel Mrzyglod 
430ab129e90SDaniel Mrzyglod 		created_pkt = rte_pktmbuf_alloc(mbuf_pool);
4316d13ea8eSOlivier Matz 		pkt_size = sizeof(struct rte_ether_hdr) +
43221ba4d57SVanshika Shukla 			sizeof(struct delay_req_msg);
43321ba4d57SVanshika Shukla 
43421ba4d57SVanshika Shukla 		if (rte_pktmbuf_append(created_pkt, pkt_size) == NULL) {
43521ba4d57SVanshika Shukla 			rte_pktmbuf_free(created_pkt);
43621ba4d57SVanshika Shukla 			return;
43721ba4d57SVanshika Shukla 		}
438ab129e90SDaniel Mrzyglod 		created_pkt->data_len = pkt_size;
439ab129e90SDaniel Mrzyglod 		created_pkt->pkt_len = pkt_size;
4406d13ea8eSOlivier Matz 		eth_hdr = rte_pktmbuf_mtod(created_pkt, struct rte_ether_hdr *);
44104d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_addr, &eth_hdr->src_addr);
442ab129e90SDaniel Mrzyglod 
443ab129e90SDaniel Mrzyglod 		/* Set multicast address 01-1B-19-00-00-00. */
44404d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_multicast, &eth_hdr->dst_addr);
445ab129e90SDaniel Mrzyglod 
446ab129e90SDaniel Mrzyglod 		eth_hdr->ether_type = htons(PTP_PROTOCOL);
44721ba4d57SVanshika Shukla 		req_msg = rte_pktmbuf_mtod_offset(created_pkt,
44821ba4d57SVanshika Shukla 			struct delay_req_msg *, sizeof(struct
44921ba4d57SVanshika Shukla 			rte_ether_hdr));
450ab129e90SDaniel Mrzyglod 
45121ba4d57SVanshika Shukla 		req_msg->hdr.seq_id = htons(ptp_data->seqID_SYNC);
45221ba4d57SVanshika Shukla 		req_msg->hdr.msg_type = DELAY_REQ;
45321ba4d57SVanshika Shukla 		req_msg->hdr.ver = 2;
45421ba4d57SVanshika Shukla 		req_msg->hdr.control = 1;
45521ba4d57SVanshika Shukla 		req_msg->hdr.log_message_interval = 127;
45621ba4d57SVanshika Shukla 		req_msg->hdr.message_length =
457376aa383SHarman Kalra 			htons(sizeof(struct delay_req_msg));
45821ba4d57SVanshika Shukla 		req_msg->hdr.domain_number = ptp_hdr->domain_number;
459ab129e90SDaniel Mrzyglod 
460ab129e90SDaniel Mrzyglod 		/* Set up clock id. */
461ab129e90SDaniel Mrzyglod 		client_clkid =
46221ba4d57SVanshika Shukla 			&req_msg->hdr.source_port_id.clock_id;
463ab129e90SDaniel Mrzyglod 
46404d43857SDmitry Kozlyuk 		client_clkid->id[0] = eth_hdr->src_addr.addr_bytes[0];
46504d43857SDmitry Kozlyuk 		client_clkid->id[1] = eth_hdr->src_addr.addr_bytes[1];
46604d43857SDmitry Kozlyuk 		client_clkid->id[2] = eth_hdr->src_addr.addr_bytes[2];
467ab129e90SDaniel Mrzyglod 		client_clkid->id[3] = 0xFF;
468ab129e90SDaniel Mrzyglod 		client_clkid->id[4] = 0xFE;
46904d43857SDmitry Kozlyuk 		client_clkid->id[5] = eth_hdr->src_addr.addr_bytes[3];
47004d43857SDmitry Kozlyuk 		client_clkid->id[6] = eth_hdr->src_addr.addr_bytes[4];
47104d43857SDmitry Kozlyuk 		client_clkid->id[7] = eth_hdr->src_addr.addr_bytes[5];
472ab129e90SDaniel Mrzyglod 
473ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->client_clock_id,
474ab129e90SDaniel Mrzyglod 			   client_clkid,
475ab129e90SDaniel Mrzyglod 			   sizeof(struct clock_id));
476ab129e90SDaniel Mrzyglod 
477ab129e90SDaniel Mrzyglod 		/* Enable flag for hardware timestamping. */
478daa02b5cSOlivier Matz 		created_pkt->ol_flags |= RTE_MBUF_F_TX_IEEE1588_TMST;
479ab129e90SDaniel Mrzyglod 
480ab129e90SDaniel Mrzyglod 		/*Read value from NIC to prevent latching with old value. */
481ab129e90SDaniel Mrzyglod 		rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
482ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3);
483ab129e90SDaniel Mrzyglod 
484ab129e90SDaniel Mrzyglod 		/* Transmit the packet. */
485ab129e90SDaniel Mrzyglod 		rte_eth_tx_burst(ptp_data->portid, 0, &created_pkt, 1);
486ab129e90SDaniel Mrzyglod 
487ab129e90SDaniel Mrzyglod 		wait_us = 0;
488ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_nsec = 0;
489ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_sec = 0;
490ab129e90SDaniel Mrzyglod 
491ab129e90SDaniel Mrzyglod 		/* Wait at least 1 us to read TX timestamp. */
492ab129e90SDaniel Mrzyglod 		while ((rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
493ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3) < 0) && (wait_us < 1000)) {
494ab129e90SDaniel Mrzyglod 			rte_delay_us(1);
495ab129e90SDaniel Mrzyglod 			wait_us++;
496ab129e90SDaniel Mrzyglod 		}
497ab129e90SDaniel Mrzyglod 	}
498ab129e90SDaniel Mrzyglod }
499ab129e90SDaniel Mrzyglod 
500ab129e90SDaniel Mrzyglod /*
501ab129e90SDaniel Mrzyglod  * Update the kernel time with the difference between it and the current NIC
502ab129e90SDaniel Mrzyglod  * time.
503ab129e90SDaniel Mrzyglod  */
504ab129e90SDaniel Mrzyglod static inline void
505ab129e90SDaniel Mrzyglod update_kernel_time(void)
506ab129e90SDaniel Mrzyglod {
507ab129e90SDaniel Mrzyglod 	int64_t nsec;
508ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
509ab129e90SDaniel Mrzyglod 
510ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
511ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data.current_ptp_port, &net_time);
512ab129e90SDaniel Mrzyglod 
513ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
514ab129e90SDaniel Mrzyglod 	       (int64_t)timespec64_to_ns(&sys_time);
515ab129e90SDaniel Mrzyglod 
516ab129e90SDaniel Mrzyglod 	ptp_data.new_adj = ns_to_timeval(nsec);
517ab129e90SDaniel Mrzyglod 
518ab129e90SDaniel Mrzyglod 	/*
519ab129e90SDaniel Mrzyglod 	 * If difference between kernel time and system time in NIC is too big
520ab129e90SDaniel Mrzyglod 	 * (more than +/- 20 microseconds), use clock_settime to set directly
521ab129e90SDaniel Mrzyglod 	 * the kernel time, as adjtime is better for small adjustments (takes
522ab129e90SDaniel Mrzyglod 	 * longer to adjust the time).
523ab129e90SDaniel Mrzyglod 	 */
524ab129e90SDaniel Mrzyglod 
525ab129e90SDaniel Mrzyglod 	if (nsec > KERNEL_TIME_ADJUST_LIMIT || nsec < -KERNEL_TIME_ADJUST_LIMIT)
526ab129e90SDaniel Mrzyglod 		clock_settime(CLOCK_REALTIME, &net_time);
527ab129e90SDaniel Mrzyglod 	else
528ab129e90SDaniel Mrzyglod 		adjtime(&ptp_data.new_adj, 0);
529ab129e90SDaniel Mrzyglod 
530ab129e90SDaniel Mrzyglod 
531ab129e90SDaniel Mrzyglod }
532ab129e90SDaniel Mrzyglod 
533ab129e90SDaniel Mrzyglod /*
534ab129e90SDaniel Mrzyglod  * Parse the DELAY_RESP message.
535ab129e90SDaniel Mrzyglod  */
536ab129e90SDaniel Mrzyglod static void
537b8d1d60fSStephen Hemminger parse_drsp(struct ptpv2_time_receiver_ordinary *ptp_data)
538ab129e90SDaniel Mrzyglod {
539ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
540ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
541ab129e90SDaniel Mrzyglod 	struct tstamp *rx_tstamp;
542ab129e90SDaniel Mrzyglod 	uint16_t seq_id;
543ab129e90SDaniel Mrzyglod 
544cebcefbaSStephen Hemminger 	ptp_msg = rte_pktmbuf_mtod_offset(m, struct ptp_message *,
5456d13ea8eSOlivier Matz 					  sizeof(struct rte_ether_hdr));
546ab129e90SDaniel Mrzyglod 	seq_id = rte_be_to_cpu_16(ptp_msg->delay_resp.hdr.seq_id);
547ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->client_clock_id,
548ab129e90SDaniel Mrzyglod 		   &ptp_msg->delay_resp.req_port_id.clock_id,
549ab129e90SDaniel Mrzyglod 		   sizeof(struct clock_id)) == 0) {
550ab129e90SDaniel Mrzyglod 		if (seq_id == ptp_data->seqID_FOLLOWUP) {
551ab129e90SDaniel Mrzyglod 			rx_tstamp = &ptp_msg->delay_resp.rx_tstamp;
552ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_nsec = ntohl(rx_tstamp->ns);
553ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec =
554ab129e90SDaniel Mrzyglod 				((uint64_t)ntohl(rx_tstamp->sec_lsb)) |
555ab129e90SDaniel Mrzyglod 				(((uint64_t)ntohs(rx_tstamp->sec_msb)) << 32);
556ab129e90SDaniel Mrzyglod 
557ab129e90SDaniel Mrzyglod 			/* Evaluate the delta for adjustment. */
558ab129e90SDaniel Mrzyglod 			ptp_data->delta = delta_eval(ptp_data);
559ab129e90SDaniel Mrzyglod 
560ab129e90SDaniel Mrzyglod 			rte_eth_timesync_adjust_time(ptp_data->portid,
561ab129e90SDaniel Mrzyglod 							ptp_data->delta);
562ab129e90SDaniel Mrzyglod 
563ab129e90SDaniel Mrzyglod 			ptp_data->current_ptp_port = ptp_data->portid;
564ab129e90SDaniel Mrzyglod 
565ab129e90SDaniel Mrzyglod 			/* Update kernel time if enabled in app parameters. */
566ab129e90SDaniel Mrzyglod 			if (ptp_data->kernel_time_set == 1)
567ab129e90SDaniel Mrzyglod 				update_kernel_time();
568ab129e90SDaniel Mrzyglod 
569ab129e90SDaniel Mrzyglod 
570ab129e90SDaniel Mrzyglod 
571ab129e90SDaniel Mrzyglod 		}
572ab129e90SDaniel Mrzyglod 	}
573ab129e90SDaniel Mrzyglod }
574ab129e90SDaniel Mrzyglod 
575b8d1d60fSStephen Hemminger /* This function processes PTP packets, implementing time receiver PTP IEEE1588 L2
576ab129e90SDaniel Mrzyglod  * functionality.
577ab129e90SDaniel Mrzyglod  */
5789a212dc0SConor Fogarty 
5799a212dc0SConor Fogarty /* Parse ptp frames. 8< */
580ab129e90SDaniel Mrzyglod static void
58147523597SZhiyong Yang parse_ptp_frames(uint16_t portid, struct rte_mbuf *m) {
582ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
5836d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
584ab129e90SDaniel Mrzyglod 	uint16_t eth_type;
585ab129e90SDaniel Mrzyglod 
5866d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
587ab129e90SDaniel Mrzyglod 	eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
588ab129e90SDaniel Mrzyglod 
589ab129e90SDaniel Mrzyglod 	if (eth_type == PTP_PROTOCOL) {
590ab129e90SDaniel Mrzyglod 		ptp_data.m = m;
591ab129e90SDaniel Mrzyglod 		ptp_data.portid = portid;
592cebcefbaSStephen Hemminger 		ptp_hdr = rte_pktmbuf_mtod_offset(m, struct ptp_header *,
593cebcefbaSStephen Hemminger 						  sizeof(struct rte_ether_hdr));
594ab129e90SDaniel Mrzyglod 
595ab129e90SDaniel Mrzyglod 		switch (ptp_hdr->msg_type) {
596ab129e90SDaniel Mrzyglod 		case SYNC:
597ab129e90SDaniel Mrzyglod 			parse_sync(&ptp_data, m->timesync);
598ab129e90SDaniel Mrzyglod 			break;
599ab129e90SDaniel Mrzyglod 		case FOLLOW_UP:
600ab129e90SDaniel Mrzyglod 			parse_fup(&ptp_data);
601ab129e90SDaniel Mrzyglod 			break;
602ab129e90SDaniel Mrzyglod 		case DELAY_RESP:
603ab129e90SDaniel Mrzyglod 			parse_drsp(&ptp_data);
604ab129e90SDaniel Mrzyglod 			print_clock_info(&ptp_data);
605ab129e90SDaniel Mrzyglod 			break;
606ab129e90SDaniel Mrzyglod 		default:
607ab129e90SDaniel Mrzyglod 			break;
608ab129e90SDaniel Mrzyglod 		}
609ab129e90SDaniel Mrzyglod 	}
610ab129e90SDaniel Mrzyglod }
6119a212dc0SConor Fogarty /* >8 End of function processes PTP packets. */
612ab129e90SDaniel Mrzyglod 
613ab129e90SDaniel Mrzyglod /*
614ab129e90SDaniel Mrzyglod  * The lcore main. This is the main thread that does the work, reading from an
615ab129e90SDaniel Mrzyglod  * input port and writing to an output port.
616ab129e90SDaniel Mrzyglod  */
6178badf48dSRahul Bhansali static void
618ab129e90SDaniel Mrzyglod lcore_main(void)
619ab129e90SDaniel Mrzyglod {
62047523597SZhiyong Yang 	uint16_t portid;
621ab129e90SDaniel Mrzyglod 	unsigned nb_rx;
622ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
623ab129e90SDaniel Mrzyglod 
624ab129e90SDaniel Mrzyglod 	printf("\nCore %u Waiting for SYNC packets. [Ctrl+C to quit]\n",
625ab129e90SDaniel Mrzyglod 			rte_lcore_id());
626ab129e90SDaniel Mrzyglod 
627ab129e90SDaniel Mrzyglod 	/* Run until the application is quit or killed. */
628ab129e90SDaniel Mrzyglod 
6298badf48dSRahul Bhansali 	while (!force_quit) {
6309a212dc0SConor Fogarty 		/* Read packet from RX queues. 8< */
631ab129e90SDaniel Mrzyglod 		for (portid = 0; portid < ptp_enabled_port_nb; portid++) {
632ab129e90SDaniel Mrzyglod 
633ab129e90SDaniel Mrzyglod 			portid = ptp_enabled_ports[portid];
634ab129e90SDaniel Mrzyglod 			nb_rx = rte_eth_rx_burst(portid, 0, &m, 1);
635ab129e90SDaniel Mrzyglod 
636ab129e90SDaniel Mrzyglod 			if (likely(nb_rx == 0))
637ab129e90SDaniel Mrzyglod 				continue;
638ab129e90SDaniel Mrzyglod 
6399a212dc0SConor Fogarty 			/* Packet is parsed to determine which type. 8< */
640daa02b5cSOlivier Matz 			if (m->ol_flags & RTE_MBUF_F_RX_IEEE1588_PTP)
641ab129e90SDaniel Mrzyglod 				parse_ptp_frames(portid, m);
6429a212dc0SConor Fogarty 			/* >8 End of packet is parsed to determine which type. */
643ab129e90SDaniel Mrzyglod 
644ab129e90SDaniel Mrzyglod 			rte_pktmbuf_free(m);
645ab129e90SDaniel Mrzyglod 		}
6469a212dc0SConor Fogarty 		/* >8 End of read packets from RX queues. */
647ab129e90SDaniel Mrzyglod 	}
648ab129e90SDaniel Mrzyglod }
649ab129e90SDaniel Mrzyglod 
650ab129e90SDaniel Mrzyglod static void
651ab129e90SDaniel Mrzyglod print_usage(const char *prgname)
652ab129e90SDaniel Mrzyglod {
653ab129e90SDaniel Mrzyglod 	printf("%s [EAL options] -- -p PORTMASK -T VALUE\n"
654ab129e90SDaniel Mrzyglod 		" -T VALUE: 0 - Disable, 1 - Enable Linux Clock"
655ab129e90SDaniel Mrzyglod 		" Synchronization (0 default)\n"
6565357e228SMingjin Ye 		" -p PORTMASK: hexadecimal bitmask of ports to configure\n",
657ab129e90SDaniel Mrzyglod 		prgname);
658ab129e90SDaniel Mrzyglod }
659ab129e90SDaniel Mrzyglod 
660ab129e90SDaniel Mrzyglod static int
661ab129e90SDaniel Mrzyglod ptp_parse_portmask(const char *portmask)
662ab129e90SDaniel Mrzyglod {
663ab129e90SDaniel Mrzyglod 	char *end = NULL;
664ab129e90SDaniel Mrzyglod 	unsigned long pm;
665ab129e90SDaniel Mrzyglod 
666ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
667ab129e90SDaniel Mrzyglod 	pm = strtoul(portmask, &end, 16);
668ab129e90SDaniel Mrzyglod 
669ab129e90SDaniel Mrzyglod 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
670ce6b8c31SSarosh Arif 		return 0;
671ab129e90SDaniel Mrzyglod 
672ab129e90SDaniel Mrzyglod 	return pm;
673ab129e90SDaniel Mrzyglod }
674ab129e90SDaniel Mrzyglod 
675ab129e90SDaniel Mrzyglod static int
676ab129e90SDaniel Mrzyglod parse_ptp_kernel(const char *param)
677ab129e90SDaniel Mrzyglod {
678ab129e90SDaniel Mrzyglod 	char *end = NULL;
679ab129e90SDaniel Mrzyglod 	unsigned long pm;
680ab129e90SDaniel Mrzyglod 
681ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
682ab129e90SDaniel Mrzyglod 	pm = strtoul(param, &end, 16);
683ab129e90SDaniel Mrzyglod 
684ab129e90SDaniel Mrzyglod 	if ((param[0] == '\0') || (end == NULL) || (*end != '\0'))
685ab129e90SDaniel Mrzyglod 		return -1;
686ab129e90SDaniel Mrzyglod 	if (pm == 0)
687ab129e90SDaniel Mrzyglod 		return 0;
688ab129e90SDaniel Mrzyglod 
689ab129e90SDaniel Mrzyglod 	return 1;
690ab129e90SDaniel Mrzyglod }
691ab129e90SDaniel Mrzyglod 
692ab129e90SDaniel Mrzyglod /* Parse the commandline arguments. */
693ab129e90SDaniel Mrzyglod static int
694ab129e90SDaniel Mrzyglod ptp_parse_args(int argc, char **argv)
695ab129e90SDaniel Mrzyglod {
696ab129e90SDaniel Mrzyglod 	int opt, ret;
697ab129e90SDaniel Mrzyglod 	char **argvopt;
698ab129e90SDaniel Mrzyglod 	int option_index;
699ab129e90SDaniel Mrzyglod 	char *prgname = argv[0];
700ab129e90SDaniel Mrzyglod 	static struct option lgopts[] = { {NULL, 0, 0, 0} };
701ab129e90SDaniel Mrzyglod 
702ab129e90SDaniel Mrzyglod 	argvopt = argv;
703ab129e90SDaniel Mrzyglod 
7045357e228SMingjin Ye 	while ((opt = getopt_long(argc, argvopt, "p:T:",
705ab129e90SDaniel Mrzyglod 				  lgopts, &option_index)) != EOF) {
706ab129e90SDaniel Mrzyglod 
707ab129e90SDaniel Mrzyglod 		switch (opt) {
708ab129e90SDaniel Mrzyglod 
709ab129e90SDaniel Mrzyglod 		/* Portmask. */
710ab129e90SDaniel Mrzyglod 		case 'p':
711ab129e90SDaniel Mrzyglod 			ptp_enabled_port_mask = ptp_parse_portmask(optarg);
712ab129e90SDaniel Mrzyglod 			if (ptp_enabled_port_mask == 0) {
713ab129e90SDaniel Mrzyglod 				printf("invalid portmask\n");
714ab129e90SDaniel Mrzyglod 				print_usage(prgname);
715ab129e90SDaniel Mrzyglod 				return -1;
716ab129e90SDaniel Mrzyglod 			}
717ab129e90SDaniel Mrzyglod 			break;
718ab129e90SDaniel Mrzyglod 		/* Time synchronization. */
719ab129e90SDaniel Mrzyglod 		case 'T':
720ab129e90SDaniel Mrzyglod 			ret = parse_ptp_kernel(optarg);
721ab129e90SDaniel Mrzyglod 			if (ret < 0) {
722ab129e90SDaniel Mrzyglod 				print_usage(prgname);
723ab129e90SDaniel Mrzyglod 				return -1;
724ab129e90SDaniel Mrzyglod 			}
725ab129e90SDaniel Mrzyglod 
726ab129e90SDaniel Mrzyglod 			ptp_data.kernel_time_set = ret;
727ab129e90SDaniel Mrzyglod 			break;
728ab129e90SDaniel Mrzyglod 
729ab129e90SDaniel Mrzyglod 		default:
730ab129e90SDaniel Mrzyglod 			print_usage(prgname);
731ab129e90SDaniel Mrzyglod 			return -1;
732ab129e90SDaniel Mrzyglod 		}
733ab129e90SDaniel Mrzyglod 	}
734ab129e90SDaniel Mrzyglod 
735ab129e90SDaniel Mrzyglod 	argv[optind-1] = prgname;
736ab129e90SDaniel Mrzyglod 
7379d5ca532SKeith Wiles 	optind = 1; /* Reset getopt lib. */
738ab129e90SDaniel Mrzyglod 
739ab129e90SDaniel Mrzyglod 	return 0;
740ab129e90SDaniel Mrzyglod }
741ab129e90SDaniel Mrzyglod 
7428badf48dSRahul Bhansali static void
7438badf48dSRahul Bhansali signal_handler(int signum)
7448badf48dSRahul Bhansali {
7458badf48dSRahul Bhansali 	if (signum == SIGINT || signum == SIGTERM)
7468badf48dSRahul Bhansali 		force_quit = true;
7478badf48dSRahul Bhansali }
7488badf48dSRahul Bhansali 
749ab129e90SDaniel Mrzyglod /*
750ab129e90SDaniel Mrzyglod  * The main function, which does initialization and calls the per-lcore
751ab129e90SDaniel Mrzyglod  * functions.
752ab129e90SDaniel Mrzyglod  */
753ab129e90SDaniel Mrzyglod int
754ab129e90SDaniel Mrzyglod main(int argc, char *argv[])
755ab129e90SDaniel Mrzyglod {
756ab129e90SDaniel Mrzyglod 	unsigned nb_ports;
757ab129e90SDaniel Mrzyglod 
75847523597SZhiyong Yang 	uint16_t portid;
759ab129e90SDaniel Mrzyglod 
7609a212dc0SConor Fogarty 	/* Initialize the Environment Abstraction Layer (EAL). 8< */
761ab129e90SDaniel Mrzyglod 	int ret = rte_eal_init(argc, argv);
762ab129e90SDaniel Mrzyglod 
763ab129e90SDaniel Mrzyglod 	if (ret < 0)
764ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
7659a212dc0SConor Fogarty 	/* >8 End of initialization of EAL. */
766ab129e90SDaniel Mrzyglod 
767b8d1d60fSStephen Hemminger 	memset(&ptp_data, 0, sizeof(struct ptpv2_time_receiver_ordinary));
768ab129e90SDaniel Mrzyglod 
7699a212dc0SConor Fogarty 	/* Parse specific arguments. 8< */
770ab129e90SDaniel Mrzyglod 	argc -= ret;
771ab129e90SDaniel Mrzyglod 	argv += ret;
772ab129e90SDaniel Mrzyglod 
7738badf48dSRahul Bhansali 	force_quit = false;
7748badf48dSRahul Bhansali 	signal(SIGINT, signal_handler);
7758badf48dSRahul Bhansali 	signal(SIGTERM, signal_handler);
7768badf48dSRahul Bhansali 
777ab129e90SDaniel Mrzyglod 	ret = ptp_parse_args(argc, argv);
778ab129e90SDaniel Mrzyglod 	if (ret < 0)
779ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
7809a212dc0SConor Fogarty 	/* >8 End of parsing specific arguments. */
781ab129e90SDaniel Mrzyglod 
782ab129e90SDaniel Mrzyglod 	/* Check that there is an even number of ports to send/receive on. */
783d9a42a69SThomas Monjalon 	nb_ports = rte_eth_dev_count_avail();
784ab129e90SDaniel Mrzyglod 
7859a212dc0SConor Fogarty 	/* Creates a new mempool in memory to hold the mbufs. 8< */
786ab129e90SDaniel Mrzyglod 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
787ab129e90SDaniel Mrzyglod 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
7889a212dc0SConor Fogarty 	/* >8 End of a new mempool in memory to hold the mbufs. */
789ab129e90SDaniel Mrzyglod 
790ab129e90SDaniel Mrzyglod 	if (mbuf_pool == NULL)
791ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
792ab129e90SDaniel Mrzyglod 
7939a212dc0SConor Fogarty 	/* Initialize all ports. 8< */
7948728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
795ab129e90SDaniel Mrzyglod 		if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
796ab129e90SDaniel Mrzyglod 			if (port_init(portid, mbuf_pool) == 0) {
797ab129e90SDaniel Mrzyglod 				ptp_enabled_ports[ptp_enabled_port_nb] = portid;
798ab129e90SDaniel Mrzyglod 				ptp_enabled_port_nb++;
799ab129e90SDaniel Mrzyglod 			} else {
800ab129e90SDaniel Mrzyglod 				rte_exit(EXIT_FAILURE,
801ab129e90SDaniel Mrzyglod 					 "Cannot init port %"PRIu8 "\n",
802ab129e90SDaniel Mrzyglod 					 portid);
803ab129e90SDaniel Mrzyglod 			}
804ab129e90SDaniel Mrzyglod 		} else
805ab129e90SDaniel Mrzyglod 			printf("Skipping disabled port %u\n", portid);
806ab129e90SDaniel Mrzyglod 	}
8079a212dc0SConor Fogarty 	/* >8 End of initialization of all ports. */
808ab129e90SDaniel Mrzyglod 
809ab129e90SDaniel Mrzyglod 	if (ptp_enabled_port_nb == 0) {
810ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE,
811ab129e90SDaniel Mrzyglod 			"All available ports are disabled."
812ab129e90SDaniel Mrzyglod 			" Please set portmask.\n");
813ab129e90SDaniel Mrzyglod 	}
814ab129e90SDaniel Mrzyglod 
815ab129e90SDaniel Mrzyglod 	if (rte_lcore_count() > 1)
816ab129e90SDaniel Mrzyglod 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
817ab129e90SDaniel Mrzyglod 
818cb056611SStephen Hemminger 	/* Call lcore_main on the main core only. */
819ab129e90SDaniel Mrzyglod 	lcore_main();
820ab129e90SDaniel Mrzyglod 
8218badf48dSRahul Bhansali 	RTE_ETH_FOREACH_DEV(portid) {
8228badf48dSRahul Bhansali 		if ((ptp_enabled_port_mask & (1 << portid)) == 0)
8238badf48dSRahul Bhansali 			continue;
8248badf48dSRahul Bhansali 
8258badf48dSRahul Bhansali 		/* Disable timesync timestamping for the Ethernet device */
8268badf48dSRahul Bhansali 		rte_eth_timesync_disable(portid);
8278badf48dSRahul Bhansali 
8288badf48dSRahul Bhansali 		ret = rte_eth_dev_stop(portid);
8298badf48dSRahul Bhansali 		if (ret != 0)
8308badf48dSRahul Bhansali 			printf("rte_eth_dev_stop: err=%d, port=%d\n", ret, portid);
8318badf48dSRahul Bhansali 
8328badf48dSRahul Bhansali 		rte_eth_dev_close(portid);
8338badf48dSRahul Bhansali 	}
8348badf48dSRahul Bhansali 
83510aa3757SChengchang Tang 	/* clean up the EAL */
83610aa3757SChengchang Tang 	rte_eal_cleanup();
83710aa3757SChengchang Tang 
838ab129e90SDaniel Mrzyglod 	return 0;
839ab129e90SDaniel Mrzyglod }
840