xref: /dpdk/examples/ptpclient/ptpclient.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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>
12ab129e90SDaniel Mrzyglod #include <inttypes.h>
13ab129e90SDaniel Mrzyglod #include <rte_eal.h>
14ab129e90SDaniel Mrzyglod #include <rte_ethdev.h>
15ab129e90SDaniel Mrzyglod #include <rte_cycles.h>
16ab129e90SDaniel Mrzyglod #include <rte_lcore.h>
17ab129e90SDaniel Mrzyglod #include <rte_mbuf.h>
18ab129e90SDaniel Mrzyglod #include <rte_ip.h>
19ab129e90SDaniel Mrzyglod #include <limits.h>
20ab129e90SDaniel Mrzyglod #include <sys/time.h>
21ab129e90SDaniel Mrzyglod #include <getopt.h>
22ab129e90SDaniel Mrzyglod 
23867a6c66SKevin Laatz #define RX_RING_SIZE 1024
24867a6c66SKevin Laatz #define TX_RING_SIZE 1024
25ab129e90SDaniel Mrzyglod 
26ab129e90SDaniel Mrzyglod #define NUM_MBUFS            8191
27ab129e90SDaniel Mrzyglod #define MBUF_CACHE_SIZE       250
28ab129e90SDaniel Mrzyglod 
29ab129e90SDaniel Mrzyglod /* Values for the PTP messageType field. */
30ab129e90SDaniel Mrzyglod #define SYNC                  0x0
31ab129e90SDaniel Mrzyglod #define DELAY_REQ             0x1
32ab129e90SDaniel Mrzyglod #define PDELAY_REQ            0x2
33ab129e90SDaniel Mrzyglod #define PDELAY_RESP           0x3
34ab129e90SDaniel Mrzyglod #define FOLLOW_UP             0x8
35ab129e90SDaniel Mrzyglod #define DELAY_RESP            0x9
36ab129e90SDaniel Mrzyglod #define PDELAY_RESP_FOLLOW_UP 0xA
37ab129e90SDaniel Mrzyglod #define ANNOUNCE              0xB
38ab129e90SDaniel Mrzyglod #define SIGNALING             0xC
39ab129e90SDaniel Mrzyglod #define MANAGEMENT            0xD
40ab129e90SDaniel Mrzyglod 
41ab129e90SDaniel Mrzyglod #define NSEC_PER_SEC        1000000000L
42ab129e90SDaniel Mrzyglod #define KERNEL_TIME_ADJUST_LIMIT  20000
43ab129e90SDaniel Mrzyglod #define PTP_PROTOCOL             0x88F7
44ab129e90SDaniel Mrzyglod 
45ab129e90SDaniel Mrzyglod struct rte_mempool *mbuf_pool;
46ab129e90SDaniel Mrzyglod uint32_t ptp_enabled_port_mask;
47ab129e90SDaniel Mrzyglod uint8_t ptp_enabled_port_nb;
48ab129e90SDaniel Mrzyglod static uint8_t ptp_enabled_ports[RTE_MAX_ETHPORTS];
49ab129e90SDaniel Mrzyglod 
506d13ea8eSOlivier Matz static const struct rte_ether_addr ether_multicast = {
51ab129e90SDaniel Mrzyglod 	.addr_bytes = {0x01, 0x1b, 0x19, 0x0, 0x0, 0x0}
52ab129e90SDaniel Mrzyglod };
53ab129e90SDaniel Mrzyglod 
54ab129e90SDaniel Mrzyglod /* Structs used for PTP handling. */
55ab129e90SDaniel Mrzyglod struct tstamp {
56ab129e90SDaniel Mrzyglod 	uint16_t   sec_msb;
57ab129e90SDaniel Mrzyglod 	uint32_t   sec_lsb;
58ab129e90SDaniel Mrzyglod 	uint32_t   ns;
59ef5baf34SThomas Monjalon }  __rte_packed;
60ab129e90SDaniel Mrzyglod 
61ab129e90SDaniel Mrzyglod struct clock_id {
62ab129e90SDaniel Mrzyglod 	uint8_t id[8];
63ab129e90SDaniel Mrzyglod };
64ab129e90SDaniel Mrzyglod 
65ab129e90SDaniel Mrzyglod struct port_id {
66ab129e90SDaniel Mrzyglod 	struct clock_id        clock_id;
67ab129e90SDaniel Mrzyglod 	uint16_t               port_number;
68ef5baf34SThomas Monjalon }  __rte_packed;
69ab129e90SDaniel Mrzyglod 
70ab129e90SDaniel Mrzyglod struct ptp_header {
71ab129e90SDaniel Mrzyglod 	uint8_t              msg_type;
72ab129e90SDaniel Mrzyglod 	uint8_t              ver;
73ab129e90SDaniel Mrzyglod 	uint16_t             message_length;
74ab129e90SDaniel Mrzyglod 	uint8_t              domain_number;
75ab129e90SDaniel Mrzyglod 	uint8_t              reserved1;
76ab129e90SDaniel Mrzyglod 	uint8_t              flag_field[2];
77ab129e90SDaniel Mrzyglod 	int64_t              correction;
78ab129e90SDaniel Mrzyglod 	uint32_t             reserved2;
79ab129e90SDaniel Mrzyglod 	struct port_id       source_port_id;
80ab129e90SDaniel Mrzyglod 	uint16_t             seq_id;
81ab129e90SDaniel Mrzyglod 	uint8_t              control;
82ab129e90SDaniel Mrzyglod 	int8_t               log_message_interval;
83ef5baf34SThomas Monjalon } __rte_packed;
84ab129e90SDaniel Mrzyglod 
85ab129e90SDaniel Mrzyglod struct sync_msg {
86ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
87ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
88ef5baf34SThomas Monjalon } __rte_packed;
89ab129e90SDaniel Mrzyglod 
90ab129e90SDaniel Mrzyglod struct follow_up_msg {
91ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
92ab129e90SDaniel Mrzyglod 	struct tstamp       precise_origin_tstamp;
93ab129e90SDaniel Mrzyglod 	uint8_t             suffix[0];
94ef5baf34SThomas Monjalon } __rte_packed;
95ab129e90SDaniel Mrzyglod 
96ab129e90SDaniel Mrzyglod struct delay_req_msg {
97ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
98ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
99ef5baf34SThomas Monjalon } __rte_packed;
100ab129e90SDaniel Mrzyglod 
101ab129e90SDaniel Mrzyglod struct delay_resp_msg {
102ab129e90SDaniel Mrzyglod 	struct ptp_header    hdr;
103ab129e90SDaniel Mrzyglod 	struct tstamp        rx_tstamp;
104ab129e90SDaniel Mrzyglod 	struct port_id       req_port_id;
105ab129e90SDaniel Mrzyglod 	uint8_t              suffix[0];
106ef5baf34SThomas Monjalon } __rte_packed;
107ab129e90SDaniel Mrzyglod 
108ab129e90SDaniel Mrzyglod struct ptp_message {
109ab129e90SDaniel Mrzyglod 	union {
110ab129e90SDaniel Mrzyglod 		struct ptp_header          header;
111ab129e90SDaniel Mrzyglod 		struct sync_msg            sync;
112ab129e90SDaniel Mrzyglod 		struct delay_req_msg       delay_req;
113ab129e90SDaniel Mrzyglod 		struct follow_up_msg       follow_up;
114ab129e90SDaniel Mrzyglod 		struct delay_resp_msg      delay_resp;
115ef5baf34SThomas Monjalon 	} __rte_packed;
116ab129e90SDaniel Mrzyglod };
117ab129e90SDaniel Mrzyglod 
118ab129e90SDaniel Mrzyglod struct ptpv2_data_slave_ordinary {
119ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
120ab129e90SDaniel Mrzyglod 	struct timespec tstamp1;
121ab129e90SDaniel Mrzyglod 	struct timespec tstamp2;
122ab129e90SDaniel Mrzyglod 	struct timespec tstamp3;
123ab129e90SDaniel Mrzyglod 	struct timespec tstamp4;
124ab129e90SDaniel Mrzyglod 	struct clock_id client_clock_id;
125ab129e90SDaniel Mrzyglod 	struct clock_id master_clock_id;
126ab129e90SDaniel Mrzyglod 	struct timeval new_adj;
127ab129e90SDaniel Mrzyglod 	int64_t delta;
128f8244c63SZhiyong Yang 	uint16_t portid;
129ab129e90SDaniel Mrzyglod 	uint16_t seqID_SYNC;
130ab129e90SDaniel Mrzyglod 	uint16_t seqID_FOLLOWUP;
131ab129e90SDaniel Mrzyglod 	uint8_t ptpset;
132ab129e90SDaniel Mrzyglod 	uint8_t kernel_time_set;
133f8244c63SZhiyong Yang 	uint16_t current_ptp_port;
134ab129e90SDaniel Mrzyglod };
135ab129e90SDaniel Mrzyglod 
136ab129e90SDaniel Mrzyglod static struct ptpv2_data_slave_ordinary ptp_data;
137ab129e90SDaniel Mrzyglod 
138ab129e90SDaniel Mrzyglod static inline uint64_t timespec64_to_ns(const struct timespec *ts)
139ab129e90SDaniel Mrzyglod {
140ab129e90SDaniel Mrzyglod 	return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
141ab129e90SDaniel Mrzyglod }
142ab129e90SDaniel Mrzyglod 
143ab129e90SDaniel Mrzyglod static struct timeval
144ab129e90SDaniel Mrzyglod ns_to_timeval(int64_t nsec)
145ab129e90SDaniel Mrzyglod {
146ab129e90SDaniel Mrzyglod 	struct timespec t_spec = {0, 0};
147ab129e90SDaniel Mrzyglod 	struct timeval t_eval = {0, 0};
148ab129e90SDaniel Mrzyglod 	int32_t rem;
149ab129e90SDaniel Mrzyglod 
150ab129e90SDaniel Mrzyglod 	if (nsec == 0)
151ab129e90SDaniel Mrzyglod 		return t_eval;
152ab129e90SDaniel Mrzyglod 	rem = nsec % NSEC_PER_SEC;
153ab129e90SDaniel Mrzyglod 	t_spec.tv_sec = nsec / NSEC_PER_SEC;
154ab129e90SDaniel Mrzyglod 
155ab129e90SDaniel Mrzyglod 	if (rem < 0) {
156ab129e90SDaniel Mrzyglod 		t_spec.tv_sec--;
157ab129e90SDaniel Mrzyglod 		rem += NSEC_PER_SEC;
158ab129e90SDaniel Mrzyglod 	}
159ab129e90SDaniel Mrzyglod 
160ab129e90SDaniel Mrzyglod 	t_spec.tv_nsec = rem;
161ab129e90SDaniel Mrzyglod 	t_eval.tv_sec = t_spec.tv_sec;
162ab129e90SDaniel Mrzyglod 	t_eval.tv_usec = t_spec.tv_nsec / 1000;
163ab129e90SDaniel Mrzyglod 
164ab129e90SDaniel Mrzyglod 	return t_eval;
165ab129e90SDaniel Mrzyglod }
166ab129e90SDaniel Mrzyglod 
167ab129e90SDaniel Mrzyglod /*
168ab129e90SDaniel Mrzyglod  * Initializes a given port using global settings and with the RX buffers
169ab129e90SDaniel Mrzyglod  * coming from the mbuf_pool passed as a parameter.
170ab129e90SDaniel Mrzyglod  */
171ab129e90SDaniel Mrzyglod static inline int
17247523597SZhiyong Yang port_init(uint16_t port, struct rte_mempool *mbuf_pool)
173ab129e90SDaniel Mrzyglod {
174ab129e90SDaniel Mrzyglod 	struct rte_eth_dev_info dev_info;
1751bb4a528SFerruh Yigit 	struct rte_eth_conf port_conf;
176ab129e90SDaniel Mrzyglod 	const uint16_t rx_rings = 1;
177ab129e90SDaniel Mrzyglod 	const uint16_t tx_rings = 1;
178ab129e90SDaniel Mrzyglod 	int retval;
179ab129e90SDaniel Mrzyglod 	uint16_t q;
18060efb44fSRoman Zhukov 	uint16_t nb_rxd = RX_RING_SIZE;
18160efb44fSRoman Zhukov 	uint16_t nb_txd = TX_RING_SIZE;
182ab129e90SDaniel Mrzyglod 
183a9dbe180SThomas Monjalon 	if (!rte_eth_dev_is_valid_port(port))
184ab129e90SDaniel Mrzyglod 		return -1;
185ab129e90SDaniel Mrzyglod 
1861bb4a528SFerruh Yigit 	memset(&port_conf, 0, sizeof(struct rte_eth_conf));
1871bb4a528SFerruh Yigit 
188089e5ed7SIvan Ilchenko 	retval = rte_eth_dev_info_get(port, &dev_info);
189089e5ed7SIvan Ilchenko 	if (retval != 0) {
190089e5ed7SIvan Ilchenko 		printf("Error during getting device (port %u) info: %s\n",
191089e5ed7SIvan Ilchenko 				port, strerror(-retval));
192089e5ed7SIvan Ilchenko 
193089e5ed7SIvan Ilchenko 		return retval;
194089e5ed7SIvan Ilchenko 	}
195089e5ed7SIvan Ilchenko 
196295968d1SFerruh Yigit 	if (dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP)
197295968d1SFerruh Yigit 		port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
1987a04a4f6SHemant Agrawal 
199295968d1SFerruh Yigit 	if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
200b960219bSShahaf Shuler 		port_conf.txmode.offloads |=
201295968d1SFerruh Yigit 			RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
2020625a29fSPablo de Lara 	/* Force full Tx path in the driver, required for IEEE1588 */
203295968d1SFerruh Yigit 	port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
204b960219bSShahaf Shuler 
205ab129e90SDaniel Mrzyglod 	/* Configure the Ethernet device. */
206ab129e90SDaniel Mrzyglod 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
207ab129e90SDaniel Mrzyglod 	if (retval != 0)
208ab129e90SDaniel Mrzyglod 		return retval;
209ab129e90SDaniel Mrzyglod 
21060efb44fSRoman Zhukov 	retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
21160efb44fSRoman Zhukov 	if (retval != 0)
21260efb44fSRoman Zhukov 		return retval;
21360efb44fSRoman Zhukov 
214ab129e90SDaniel Mrzyglod 	/* Allocate and set up 1 RX queue per Ethernet port. */
215ab129e90SDaniel Mrzyglod 	for (q = 0; q < rx_rings; q++) {
21692854ed2SSimei Su 		struct rte_eth_rxconf *rxconf;
21792854ed2SSimei Su 
21892854ed2SSimei Su 		rxconf = &dev_info.default_rxconf;
21992854ed2SSimei Su 		rxconf->offloads = port_conf.rxmode.offloads;
22092854ed2SSimei Su 
22160efb44fSRoman Zhukov 		retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
22292854ed2SSimei Su 				rte_eth_dev_socket_id(port), rxconf, mbuf_pool);
223ab129e90SDaniel Mrzyglod 
224ab129e90SDaniel Mrzyglod 		if (retval < 0)
225ab129e90SDaniel Mrzyglod 			return retval;
226ab129e90SDaniel Mrzyglod 	}
227ab129e90SDaniel Mrzyglod 
228ab129e90SDaniel Mrzyglod 	/* Allocate and set up 1 TX queue per Ethernet port. */
229ab129e90SDaniel Mrzyglod 	for (q = 0; q < tx_rings; q++) {
230ab129e90SDaniel Mrzyglod 		struct rte_eth_txconf *txconf;
231ab129e90SDaniel Mrzyglod 
232ab129e90SDaniel Mrzyglod 		txconf = &dev_info.default_txconf;
233b960219bSShahaf Shuler 		txconf->offloads = port_conf.txmode.offloads;
234ab129e90SDaniel Mrzyglod 
23560efb44fSRoman Zhukov 		retval = rte_eth_tx_queue_setup(port, q, nb_txd,
236ab129e90SDaniel Mrzyglod 				rte_eth_dev_socket_id(port), txconf);
237ab129e90SDaniel Mrzyglod 		if (retval < 0)
238ab129e90SDaniel Mrzyglod 			return retval;
239ab129e90SDaniel Mrzyglod 	}
240ab129e90SDaniel Mrzyglod 
241ab129e90SDaniel Mrzyglod 	/* Start the Ethernet port. */
242ab129e90SDaniel Mrzyglod 	retval = rte_eth_dev_start(port);
243ab129e90SDaniel Mrzyglod 	if (retval < 0)
244ab129e90SDaniel Mrzyglod 		return retval;
245ab129e90SDaniel Mrzyglod 
246ab129e90SDaniel Mrzyglod 	/* Enable timesync timestamping for the Ethernet device */
247376aa383SHarman Kalra 	retval = rte_eth_timesync_enable(port);
248376aa383SHarman Kalra 	if (retval < 0) {
249376aa383SHarman Kalra 		printf("Timesync enable failed: %d\n", retval);
250376aa383SHarman Kalra 		return retval;
251376aa383SHarman Kalra 	}
252ab129e90SDaniel Mrzyglod 
253ab129e90SDaniel Mrzyglod 	/* Enable RX in promiscuous mode for the Ethernet device. */
254f430bbceSIvan Ilchenko 	retval = rte_eth_promiscuous_enable(port);
255f430bbceSIvan Ilchenko 	if (retval != 0) {
256f430bbceSIvan Ilchenko 		printf("Promiscuous mode enable failed: %s\n",
257f430bbceSIvan Ilchenko 			rte_strerror(-retval));
258f430bbceSIvan Ilchenko 		return retval;
259f430bbceSIvan Ilchenko 	}
260ab129e90SDaniel Mrzyglod 
261ab129e90SDaniel Mrzyglod 	return 0;
262ab129e90SDaniel Mrzyglod }
263ab129e90SDaniel Mrzyglod 
264ab129e90SDaniel Mrzyglod static void
265ab129e90SDaniel Mrzyglod print_clock_info(struct ptpv2_data_slave_ordinary *ptp_data)
266ab129e90SDaniel Mrzyglod {
267ab129e90SDaniel Mrzyglod 	int64_t nsec;
268ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
269ab129e90SDaniel Mrzyglod 
270ab129e90SDaniel Mrzyglod 	printf("Master Clock id: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
271ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[0],
272ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[1],
273ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[2],
274ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[3],
275ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[4],
276ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[5],
277ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[6],
278ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[7]);
279ab129e90SDaniel Mrzyglod 
280ab129e90SDaniel Mrzyglod 	printf("\nT2 - Slave  Clock.  %lds %ldns",
281ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_sec),
282ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_nsec));
283ab129e90SDaniel Mrzyglod 
284ab129e90SDaniel Mrzyglod 	printf("\nT1 - Master Clock.  %lds %ldns ",
285ab129e90SDaniel Mrzyglod 			ptp_data->tstamp1.tv_sec,
286ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp1.tv_nsec));
287ab129e90SDaniel Mrzyglod 
288ab129e90SDaniel Mrzyglod 	printf("\nT3 - Slave  Clock.  %lds %ldns",
289ab129e90SDaniel Mrzyglod 			ptp_data->tstamp3.tv_sec,
290ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp3.tv_nsec));
291ab129e90SDaniel Mrzyglod 
292ab129e90SDaniel Mrzyglod 	printf("\nT4 - Master Clock.  %lds %ldns ",
293ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec,
294ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp4.tv_nsec));
295ab129e90SDaniel Mrzyglod 
296ab129e90SDaniel Mrzyglod 	printf("\nDelta between master and slave clocks:%"PRId64"ns\n",
297ab129e90SDaniel Mrzyglod 			ptp_data->delta);
298ab129e90SDaniel Mrzyglod 
299ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
300ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data->current_ptp_port, &net_time);
301ab129e90SDaniel Mrzyglod 
302ab129e90SDaniel Mrzyglod 	time_t ts = net_time.tv_sec;
303ab129e90SDaniel Mrzyglod 
304ab129e90SDaniel Mrzyglod 	printf("\n\nComparison between Linux kernel Time and PTP:");
305ab129e90SDaniel Mrzyglod 
306ab129e90SDaniel Mrzyglod 	printf("\nCurrent PTP Time: %.24s %.9ld ns",
307ab129e90SDaniel Mrzyglod 			ctime(&ts), net_time.tv_nsec);
308ab129e90SDaniel Mrzyglod 
309ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
310ab129e90SDaniel Mrzyglod 			(int64_t)timespec64_to_ns(&sys_time);
311ab129e90SDaniel Mrzyglod 	ptp_data->new_adj = ns_to_timeval(nsec);
312ab129e90SDaniel Mrzyglod 
313ab129e90SDaniel Mrzyglod 	gettimeofday(&ptp_data->new_adj, NULL);
314ab129e90SDaniel Mrzyglod 
315ab129e90SDaniel Mrzyglod 	time_t tp = ptp_data->new_adj.tv_sec;
316ab129e90SDaniel Mrzyglod 
317ab129e90SDaniel Mrzyglod 	printf("\nCurrent SYS Time: %.24s %.6ld ns",
318ab129e90SDaniel Mrzyglod 				ctime(&tp), ptp_data->new_adj.tv_usec);
319ab129e90SDaniel Mrzyglod 
320ab129e90SDaniel Mrzyglod 	printf("\nDelta between PTP and Linux Kernel time:%"PRId64"ns\n",
321ab129e90SDaniel Mrzyglod 				nsec);
322ab129e90SDaniel Mrzyglod 
323ab129e90SDaniel Mrzyglod 	printf("[Ctrl+C to quit]\n");
324ab129e90SDaniel Mrzyglod 
325ab129e90SDaniel Mrzyglod 	/* Clear screen and put cursor in column 1, row 1 */
326ab129e90SDaniel Mrzyglod 	printf("\033[2J\033[1;1H");
327ab129e90SDaniel Mrzyglod }
328ab129e90SDaniel Mrzyglod 
329ab129e90SDaniel Mrzyglod static int64_t
330ab129e90SDaniel Mrzyglod delta_eval(struct ptpv2_data_slave_ordinary *ptp_data)
331ab129e90SDaniel Mrzyglod {
332ab129e90SDaniel Mrzyglod 	int64_t delta;
333ab129e90SDaniel Mrzyglod 	uint64_t t1 = 0;
334ab129e90SDaniel Mrzyglod 	uint64_t t2 = 0;
335ab129e90SDaniel Mrzyglod 	uint64_t t3 = 0;
336ab129e90SDaniel Mrzyglod 	uint64_t t4 = 0;
337ab129e90SDaniel Mrzyglod 
338ab129e90SDaniel Mrzyglod 	t1 = timespec64_to_ns(&ptp_data->tstamp1);
339ab129e90SDaniel Mrzyglod 	t2 = timespec64_to_ns(&ptp_data->tstamp2);
340ab129e90SDaniel Mrzyglod 	t3 = timespec64_to_ns(&ptp_data->tstamp3);
341ab129e90SDaniel Mrzyglod 	t4 = timespec64_to_ns(&ptp_data->tstamp4);
342ab129e90SDaniel Mrzyglod 
343ab129e90SDaniel Mrzyglod 	delta = -((int64_t)((t2 - t1) - (t4 - t3))) / 2;
344ab129e90SDaniel Mrzyglod 
345ab129e90SDaniel Mrzyglod 	return delta;
346ab129e90SDaniel Mrzyglod }
347ab129e90SDaniel Mrzyglod 
348ab129e90SDaniel Mrzyglod /*
349ab129e90SDaniel Mrzyglod  * Parse the PTP SYNC message.
350ab129e90SDaniel Mrzyglod  */
351ab129e90SDaniel Mrzyglod static void
352ab129e90SDaniel Mrzyglod parse_sync(struct ptpv2_data_slave_ordinary *ptp_data, uint16_t rx_tstamp_idx)
353ab129e90SDaniel Mrzyglod {
354ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
355ab129e90SDaniel Mrzyglod 
356ab129e90SDaniel Mrzyglod 	ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(ptp_data->m, char *)
3576d13ea8eSOlivier Matz 			+ sizeof(struct rte_ether_hdr));
358ab129e90SDaniel Mrzyglod 	ptp_data->seqID_SYNC = rte_be_to_cpu_16(ptp_hdr->seq_id);
359ab129e90SDaniel Mrzyglod 
360ab129e90SDaniel Mrzyglod 	if (ptp_data->ptpset == 0) {
361ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->master_clock_id,
362ab129e90SDaniel Mrzyglod 				&ptp_hdr->source_port_id.clock_id,
363ab129e90SDaniel Mrzyglod 				sizeof(struct clock_id));
364ab129e90SDaniel Mrzyglod 		ptp_data->ptpset = 1;
365ab129e90SDaniel Mrzyglod 	}
366ab129e90SDaniel Mrzyglod 
367ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_hdr->source_port_id.clock_id,
368ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
369ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) == 0) {
370ab129e90SDaniel Mrzyglod 
371ab129e90SDaniel Mrzyglod 		if (ptp_data->ptpset == 1)
372ab129e90SDaniel Mrzyglod 			rte_eth_timesync_read_rx_timestamp(ptp_data->portid,
373ab129e90SDaniel Mrzyglod 					&ptp_data->tstamp2, rx_tstamp_idx);
374ab129e90SDaniel Mrzyglod 	}
375ab129e90SDaniel Mrzyglod 
376ab129e90SDaniel Mrzyglod }
377ab129e90SDaniel Mrzyglod 
378ab129e90SDaniel Mrzyglod /*
379cb056611SStephen Hemminger  * Parse the PTP FOLLOWUP message and send DELAY_REQ to the main clock.
380ab129e90SDaniel Mrzyglod  */
381ab129e90SDaniel Mrzyglod static void
382ab129e90SDaniel Mrzyglod parse_fup(struct ptpv2_data_slave_ordinary *ptp_data)
383ab129e90SDaniel Mrzyglod {
3846d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
38570febdcfSIgor Romanov 	struct rte_ether_addr eth_addr;
386ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
387ab129e90SDaniel Mrzyglod 	struct clock_id *client_clkid;
388ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
389ab129e90SDaniel Mrzyglod 	struct rte_mbuf *created_pkt;
390ab129e90SDaniel Mrzyglod 	struct tstamp *origin_tstamp;
3916d13ea8eSOlivier Matz 	struct rte_ether_addr eth_multicast = ether_multicast;
392ab129e90SDaniel Mrzyglod 	size_t pkt_size;
393ab129e90SDaniel Mrzyglod 	int wait_us;
394ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
39570febdcfSIgor Romanov 	int ret;
396ab129e90SDaniel Mrzyglod 
3976d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
398ab129e90SDaniel Mrzyglod 	ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(m, char *)
3996d13ea8eSOlivier Matz 			+ sizeof(struct rte_ether_hdr));
400ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->master_clock_id,
401ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
402ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) != 0)
403ab129e90SDaniel Mrzyglod 		return;
404ab129e90SDaniel Mrzyglod 
405ab129e90SDaniel Mrzyglod 	ptp_data->seqID_FOLLOWUP = rte_be_to_cpu_16(ptp_hdr->seq_id);
406ab129e90SDaniel Mrzyglod 	ptp_msg = (struct ptp_message *) (rte_pktmbuf_mtod(m, char *) +
4076d13ea8eSOlivier Matz 					  sizeof(struct rte_ether_hdr));
408ab129e90SDaniel Mrzyglod 
409ab129e90SDaniel Mrzyglod 	origin_tstamp = &ptp_msg->follow_up.precise_origin_tstamp;
410ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_nsec = ntohl(origin_tstamp->ns);
411ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_sec =
412ab129e90SDaniel Mrzyglod 		((uint64_t)ntohl(origin_tstamp->sec_lsb)) |
413ab129e90SDaniel Mrzyglod 		(((uint64_t)ntohs(origin_tstamp->sec_msb)) << 32);
414ab129e90SDaniel Mrzyglod 
415ab129e90SDaniel Mrzyglod 	if (ptp_data->seqID_FOLLOWUP == ptp_data->seqID_SYNC) {
41670febdcfSIgor Romanov 		ret = rte_eth_macaddr_get(ptp_data->portid, &eth_addr);
41770febdcfSIgor Romanov 		if (ret != 0) {
41870febdcfSIgor Romanov 			printf("\nCore %u: port %u failed to get MAC address: %s\n",
41970febdcfSIgor Romanov 				rte_lcore_id(), ptp_data->portid,
42070febdcfSIgor Romanov 				rte_strerror(-ret));
42170febdcfSIgor Romanov 			return;
42270febdcfSIgor Romanov 		}
423ab129e90SDaniel Mrzyglod 
424ab129e90SDaniel Mrzyglod 		created_pkt = rte_pktmbuf_alloc(mbuf_pool);
4256d13ea8eSOlivier Matz 		pkt_size = sizeof(struct rte_ether_hdr) +
426ab129e90SDaniel Mrzyglod 			sizeof(struct ptp_message);
427ab129e90SDaniel Mrzyglod 		created_pkt->data_len = pkt_size;
428ab129e90SDaniel Mrzyglod 		created_pkt->pkt_len = pkt_size;
4296d13ea8eSOlivier Matz 		eth_hdr = rte_pktmbuf_mtod(created_pkt, struct rte_ether_hdr *);
43004d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_addr, &eth_hdr->src_addr);
431ab129e90SDaniel Mrzyglod 
432ab129e90SDaniel Mrzyglod 		/* Set multicast address 01-1B-19-00-00-00. */
43304d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_multicast, &eth_hdr->dst_addr);
434ab129e90SDaniel Mrzyglod 
435ab129e90SDaniel Mrzyglod 		eth_hdr->ether_type = htons(PTP_PROTOCOL);
436ab129e90SDaniel Mrzyglod 		ptp_msg = (struct ptp_message *)
437ab129e90SDaniel Mrzyglod 			(rte_pktmbuf_mtod(created_pkt, char *) +
4386d13ea8eSOlivier Matz 			sizeof(struct rte_ether_hdr));
439ab129e90SDaniel Mrzyglod 
440ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.seq_id = htons(ptp_data->seqID_SYNC);
441ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.msg_type = DELAY_REQ;
442ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.ver = 2;
443ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.control = 1;
444ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.log_message_interval = 127;
445376aa383SHarman Kalra 		ptp_msg->delay_req.hdr.message_length =
446376aa383SHarman Kalra 			htons(sizeof(struct delay_req_msg));
447376aa383SHarman Kalra 		ptp_msg->delay_req.hdr.domain_number = ptp_hdr->domain_number;
448ab129e90SDaniel Mrzyglod 
449ab129e90SDaniel Mrzyglod 		/* Set up clock id. */
450ab129e90SDaniel Mrzyglod 		client_clkid =
451ab129e90SDaniel Mrzyglod 			&ptp_msg->delay_req.hdr.source_port_id.clock_id;
452ab129e90SDaniel Mrzyglod 
45304d43857SDmitry Kozlyuk 		client_clkid->id[0] = eth_hdr->src_addr.addr_bytes[0];
45404d43857SDmitry Kozlyuk 		client_clkid->id[1] = eth_hdr->src_addr.addr_bytes[1];
45504d43857SDmitry Kozlyuk 		client_clkid->id[2] = eth_hdr->src_addr.addr_bytes[2];
456ab129e90SDaniel Mrzyglod 		client_clkid->id[3] = 0xFF;
457ab129e90SDaniel Mrzyglod 		client_clkid->id[4] = 0xFE;
45804d43857SDmitry Kozlyuk 		client_clkid->id[5] = eth_hdr->src_addr.addr_bytes[3];
45904d43857SDmitry Kozlyuk 		client_clkid->id[6] = eth_hdr->src_addr.addr_bytes[4];
46004d43857SDmitry Kozlyuk 		client_clkid->id[7] = eth_hdr->src_addr.addr_bytes[5];
461ab129e90SDaniel Mrzyglod 
462ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->client_clock_id,
463ab129e90SDaniel Mrzyglod 			   client_clkid,
464ab129e90SDaniel Mrzyglod 			   sizeof(struct clock_id));
465ab129e90SDaniel Mrzyglod 
466ab129e90SDaniel Mrzyglod 		/* Enable flag for hardware timestamping. */
467*daa02b5cSOlivier Matz 		created_pkt->ol_flags |= RTE_MBUF_F_TX_IEEE1588_TMST;
468ab129e90SDaniel Mrzyglod 
469ab129e90SDaniel Mrzyglod 		/*Read value from NIC to prevent latching with old value. */
470ab129e90SDaniel Mrzyglod 		rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
471ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3);
472ab129e90SDaniel Mrzyglod 
473ab129e90SDaniel Mrzyglod 		/* Transmit the packet. */
474ab129e90SDaniel Mrzyglod 		rte_eth_tx_burst(ptp_data->portid, 0, &created_pkt, 1);
475ab129e90SDaniel Mrzyglod 
476ab129e90SDaniel Mrzyglod 		wait_us = 0;
477ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_nsec = 0;
478ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_sec = 0;
479ab129e90SDaniel Mrzyglod 
480ab129e90SDaniel Mrzyglod 		/* Wait at least 1 us to read TX timestamp. */
481ab129e90SDaniel Mrzyglod 		while ((rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
482ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3) < 0) && (wait_us < 1000)) {
483ab129e90SDaniel Mrzyglod 			rte_delay_us(1);
484ab129e90SDaniel Mrzyglod 			wait_us++;
485ab129e90SDaniel Mrzyglod 		}
486ab129e90SDaniel Mrzyglod 	}
487ab129e90SDaniel Mrzyglod }
488ab129e90SDaniel Mrzyglod 
489ab129e90SDaniel Mrzyglod /*
490ab129e90SDaniel Mrzyglod  * Update the kernel time with the difference between it and the current NIC
491ab129e90SDaniel Mrzyglod  * time.
492ab129e90SDaniel Mrzyglod  */
493ab129e90SDaniel Mrzyglod static inline void
494ab129e90SDaniel Mrzyglod update_kernel_time(void)
495ab129e90SDaniel Mrzyglod {
496ab129e90SDaniel Mrzyglod 	int64_t nsec;
497ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
498ab129e90SDaniel Mrzyglod 
499ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
500ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data.current_ptp_port, &net_time);
501ab129e90SDaniel Mrzyglod 
502ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
503ab129e90SDaniel Mrzyglod 	       (int64_t)timespec64_to_ns(&sys_time);
504ab129e90SDaniel Mrzyglod 
505ab129e90SDaniel Mrzyglod 	ptp_data.new_adj = ns_to_timeval(nsec);
506ab129e90SDaniel Mrzyglod 
507ab129e90SDaniel Mrzyglod 	/*
508ab129e90SDaniel Mrzyglod 	 * If difference between kernel time and system time in NIC is too big
509ab129e90SDaniel Mrzyglod 	 * (more than +/- 20 microseconds), use clock_settime to set directly
510ab129e90SDaniel Mrzyglod 	 * the kernel time, as adjtime is better for small adjustments (takes
511ab129e90SDaniel Mrzyglod 	 * longer to adjust the time).
512ab129e90SDaniel Mrzyglod 	 */
513ab129e90SDaniel Mrzyglod 
514ab129e90SDaniel Mrzyglod 	if (nsec > KERNEL_TIME_ADJUST_LIMIT || nsec < -KERNEL_TIME_ADJUST_LIMIT)
515ab129e90SDaniel Mrzyglod 		clock_settime(CLOCK_REALTIME, &net_time);
516ab129e90SDaniel Mrzyglod 	else
517ab129e90SDaniel Mrzyglod 		adjtime(&ptp_data.new_adj, 0);
518ab129e90SDaniel Mrzyglod 
519ab129e90SDaniel Mrzyglod 
520ab129e90SDaniel Mrzyglod }
521ab129e90SDaniel Mrzyglod 
522ab129e90SDaniel Mrzyglod /*
523ab129e90SDaniel Mrzyglod  * Parse the DELAY_RESP message.
524ab129e90SDaniel Mrzyglod  */
525ab129e90SDaniel Mrzyglod static void
526ab129e90SDaniel Mrzyglod parse_drsp(struct ptpv2_data_slave_ordinary *ptp_data)
527ab129e90SDaniel Mrzyglod {
528ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
529ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
530ab129e90SDaniel Mrzyglod 	struct tstamp *rx_tstamp;
531ab129e90SDaniel Mrzyglod 	uint16_t seq_id;
532ab129e90SDaniel Mrzyglod 
533ab129e90SDaniel Mrzyglod 	ptp_msg = (struct ptp_message *) (rte_pktmbuf_mtod(m, char *) +
5346d13ea8eSOlivier Matz 					sizeof(struct rte_ether_hdr));
535ab129e90SDaniel Mrzyglod 	seq_id = rte_be_to_cpu_16(ptp_msg->delay_resp.hdr.seq_id);
536ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->client_clock_id,
537ab129e90SDaniel Mrzyglod 		   &ptp_msg->delay_resp.req_port_id.clock_id,
538ab129e90SDaniel Mrzyglod 		   sizeof(struct clock_id)) == 0) {
539ab129e90SDaniel Mrzyglod 		if (seq_id == ptp_data->seqID_FOLLOWUP) {
540ab129e90SDaniel Mrzyglod 			rx_tstamp = &ptp_msg->delay_resp.rx_tstamp;
541ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_nsec = ntohl(rx_tstamp->ns);
542ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec =
543ab129e90SDaniel Mrzyglod 				((uint64_t)ntohl(rx_tstamp->sec_lsb)) |
544ab129e90SDaniel Mrzyglod 				(((uint64_t)ntohs(rx_tstamp->sec_msb)) << 32);
545ab129e90SDaniel Mrzyglod 
546ab129e90SDaniel Mrzyglod 			/* Evaluate the delta for adjustment. */
547ab129e90SDaniel Mrzyglod 			ptp_data->delta = delta_eval(ptp_data);
548ab129e90SDaniel Mrzyglod 
549ab129e90SDaniel Mrzyglod 			rte_eth_timesync_adjust_time(ptp_data->portid,
550ab129e90SDaniel Mrzyglod 						     ptp_data->delta);
551ab129e90SDaniel Mrzyglod 
552ab129e90SDaniel Mrzyglod 			ptp_data->current_ptp_port = ptp_data->portid;
553ab129e90SDaniel Mrzyglod 
554ab129e90SDaniel Mrzyglod 			/* Update kernel time if enabled in app parameters. */
555ab129e90SDaniel Mrzyglod 			if (ptp_data->kernel_time_set == 1)
556ab129e90SDaniel Mrzyglod 				update_kernel_time();
557ab129e90SDaniel Mrzyglod 
558ab129e90SDaniel Mrzyglod 
559ab129e90SDaniel Mrzyglod 
560ab129e90SDaniel Mrzyglod 		}
561ab129e90SDaniel Mrzyglod 	}
562ab129e90SDaniel Mrzyglod }
563ab129e90SDaniel Mrzyglod 
564ab129e90SDaniel Mrzyglod /* This function processes PTP packets, implementing slave PTP IEEE1588 L2
565ab129e90SDaniel Mrzyglod  * functionality.
566ab129e90SDaniel Mrzyglod  */
5679a212dc0SConor Fogarty 
5689a212dc0SConor Fogarty /* Parse ptp frames. 8< */
569ab129e90SDaniel Mrzyglod static void
57047523597SZhiyong Yang parse_ptp_frames(uint16_t portid, struct rte_mbuf *m) {
571ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
5726d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
573ab129e90SDaniel Mrzyglod 	uint16_t eth_type;
574ab129e90SDaniel Mrzyglod 
5756d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
576ab129e90SDaniel Mrzyglod 	eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
577ab129e90SDaniel Mrzyglod 
578ab129e90SDaniel Mrzyglod 	if (eth_type == PTP_PROTOCOL) {
579ab129e90SDaniel Mrzyglod 		ptp_data.m = m;
580ab129e90SDaniel Mrzyglod 		ptp_data.portid = portid;
581ab129e90SDaniel Mrzyglod 		ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(m, char *)
5826d13ea8eSOlivier Matz 					+ sizeof(struct rte_ether_hdr));
583ab129e90SDaniel Mrzyglod 
584ab129e90SDaniel Mrzyglod 		switch (ptp_hdr->msg_type) {
585ab129e90SDaniel Mrzyglod 		case SYNC:
586ab129e90SDaniel Mrzyglod 			parse_sync(&ptp_data, m->timesync);
587ab129e90SDaniel Mrzyglod 			break;
588ab129e90SDaniel Mrzyglod 		case FOLLOW_UP:
589ab129e90SDaniel Mrzyglod 			parse_fup(&ptp_data);
590ab129e90SDaniel Mrzyglod 			break;
591ab129e90SDaniel Mrzyglod 		case DELAY_RESP:
592ab129e90SDaniel Mrzyglod 			parse_drsp(&ptp_data);
593ab129e90SDaniel Mrzyglod 			print_clock_info(&ptp_data);
594ab129e90SDaniel Mrzyglod 			break;
595ab129e90SDaniel Mrzyglod 		default:
596ab129e90SDaniel Mrzyglod 			break;
597ab129e90SDaniel Mrzyglod 		}
598ab129e90SDaniel Mrzyglod 	}
599ab129e90SDaniel Mrzyglod }
6009a212dc0SConor Fogarty /* >8 End of function processes PTP packets. */
601ab129e90SDaniel Mrzyglod 
602ab129e90SDaniel Mrzyglod /*
603ab129e90SDaniel Mrzyglod  * The lcore main. This is the main thread that does the work, reading from an
604ab129e90SDaniel Mrzyglod  * input port and writing to an output port.
605ab129e90SDaniel Mrzyglod  */
606ddcd7640SThomas Monjalon static __rte_noreturn void
607ab129e90SDaniel Mrzyglod lcore_main(void)
608ab129e90SDaniel Mrzyglod {
60947523597SZhiyong Yang 	uint16_t portid;
610ab129e90SDaniel Mrzyglod 	unsigned nb_rx;
611ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
612ab129e90SDaniel Mrzyglod 
613ab129e90SDaniel Mrzyglod 	printf("\nCore %u Waiting for SYNC packets. [Ctrl+C to quit]\n",
614ab129e90SDaniel Mrzyglod 			rte_lcore_id());
615ab129e90SDaniel Mrzyglod 
616ab129e90SDaniel Mrzyglod 	/* Run until the application is quit or killed. */
617ab129e90SDaniel Mrzyglod 
618ab129e90SDaniel Mrzyglod 	while (1) {
6199a212dc0SConor Fogarty 		/* Read packet from RX queues. 8< */
620ab129e90SDaniel Mrzyglod 		for (portid = 0; portid < ptp_enabled_port_nb; portid++) {
621ab129e90SDaniel Mrzyglod 
622ab129e90SDaniel Mrzyglod 			portid = ptp_enabled_ports[portid];
623ab129e90SDaniel Mrzyglod 			nb_rx = rte_eth_rx_burst(portid, 0, &m, 1);
624ab129e90SDaniel Mrzyglod 
625ab129e90SDaniel Mrzyglod 			if (likely(nb_rx == 0))
626ab129e90SDaniel Mrzyglod 				continue;
627ab129e90SDaniel Mrzyglod 
6289a212dc0SConor Fogarty 			/* Packet is parsed to determine which type. 8< */
629*daa02b5cSOlivier Matz 			if (m->ol_flags & RTE_MBUF_F_RX_IEEE1588_PTP)
630ab129e90SDaniel Mrzyglod 				parse_ptp_frames(portid, m);
6319a212dc0SConor Fogarty 			/* >8 End of packet is parsed to determine which type. */
632ab129e90SDaniel Mrzyglod 
633ab129e90SDaniel Mrzyglod 			rte_pktmbuf_free(m);
634ab129e90SDaniel Mrzyglod 		}
6359a212dc0SConor Fogarty 		/* >8 End of read packets from RX queues. */
636ab129e90SDaniel Mrzyglod 	}
637ab129e90SDaniel Mrzyglod }
638ab129e90SDaniel Mrzyglod 
639ab129e90SDaniel Mrzyglod static void
640ab129e90SDaniel Mrzyglod print_usage(const char *prgname)
641ab129e90SDaniel Mrzyglod {
642ab129e90SDaniel Mrzyglod 	printf("%s [EAL options] -- -p PORTMASK -T VALUE\n"
643ab129e90SDaniel Mrzyglod 		" -T VALUE: 0 - Disable, 1 - Enable Linux Clock"
644ab129e90SDaniel Mrzyglod 		" Synchronization (0 default)\n"
645ab129e90SDaniel Mrzyglod 		" -p PORTMASK: hexadecimal bitmask of ports to configure\n",
646ab129e90SDaniel Mrzyglod 		prgname);
647ab129e90SDaniel Mrzyglod }
648ab129e90SDaniel Mrzyglod 
649ab129e90SDaniel Mrzyglod static int
650ab129e90SDaniel Mrzyglod ptp_parse_portmask(const char *portmask)
651ab129e90SDaniel Mrzyglod {
652ab129e90SDaniel Mrzyglod 	char *end = NULL;
653ab129e90SDaniel Mrzyglod 	unsigned long pm;
654ab129e90SDaniel Mrzyglod 
655ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
656ab129e90SDaniel Mrzyglod 	pm = strtoul(portmask, &end, 16);
657ab129e90SDaniel Mrzyglod 
658ab129e90SDaniel Mrzyglod 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
659ce6b8c31SSarosh Arif 		return 0;
660ab129e90SDaniel Mrzyglod 
661ab129e90SDaniel Mrzyglod 	return pm;
662ab129e90SDaniel Mrzyglod }
663ab129e90SDaniel Mrzyglod 
664ab129e90SDaniel Mrzyglod static int
665ab129e90SDaniel Mrzyglod parse_ptp_kernel(const char *param)
666ab129e90SDaniel Mrzyglod {
667ab129e90SDaniel Mrzyglod 	char *end = NULL;
668ab129e90SDaniel Mrzyglod 	unsigned long pm;
669ab129e90SDaniel Mrzyglod 
670ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
671ab129e90SDaniel Mrzyglod 	pm = strtoul(param, &end, 16);
672ab129e90SDaniel Mrzyglod 
673ab129e90SDaniel Mrzyglod 	if ((param[0] == '\0') || (end == NULL) || (*end != '\0'))
674ab129e90SDaniel Mrzyglod 		return -1;
675ab129e90SDaniel Mrzyglod 	if (pm == 0)
676ab129e90SDaniel Mrzyglod 		return 0;
677ab129e90SDaniel Mrzyglod 
678ab129e90SDaniel Mrzyglod 	return 1;
679ab129e90SDaniel Mrzyglod }
680ab129e90SDaniel Mrzyglod 
681ab129e90SDaniel Mrzyglod /* Parse the commandline arguments. */
682ab129e90SDaniel Mrzyglod static int
683ab129e90SDaniel Mrzyglod ptp_parse_args(int argc, char **argv)
684ab129e90SDaniel Mrzyglod {
685ab129e90SDaniel Mrzyglod 	int opt, ret;
686ab129e90SDaniel Mrzyglod 	char **argvopt;
687ab129e90SDaniel Mrzyglod 	int option_index;
688ab129e90SDaniel Mrzyglod 	char *prgname = argv[0];
689ab129e90SDaniel Mrzyglod 	static struct option lgopts[] = { {NULL, 0, 0, 0} };
690ab129e90SDaniel Mrzyglod 
691ab129e90SDaniel Mrzyglod 	argvopt = argv;
692ab129e90SDaniel Mrzyglod 
693ab129e90SDaniel Mrzyglod 	while ((opt = getopt_long(argc, argvopt, "p:T:",
694ab129e90SDaniel Mrzyglod 				  lgopts, &option_index)) != EOF) {
695ab129e90SDaniel Mrzyglod 
696ab129e90SDaniel Mrzyglod 		switch (opt) {
697ab129e90SDaniel Mrzyglod 
698ab129e90SDaniel Mrzyglod 		/* Portmask. */
699ab129e90SDaniel Mrzyglod 		case 'p':
700ab129e90SDaniel Mrzyglod 			ptp_enabled_port_mask = ptp_parse_portmask(optarg);
701ab129e90SDaniel Mrzyglod 			if (ptp_enabled_port_mask == 0) {
702ab129e90SDaniel Mrzyglod 				printf("invalid portmask\n");
703ab129e90SDaniel Mrzyglod 				print_usage(prgname);
704ab129e90SDaniel Mrzyglod 				return -1;
705ab129e90SDaniel Mrzyglod 			}
706ab129e90SDaniel Mrzyglod 			break;
707ab129e90SDaniel Mrzyglod 		/* Time synchronization. */
708ab129e90SDaniel Mrzyglod 		case 'T':
709ab129e90SDaniel Mrzyglod 			ret = parse_ptp_kernel(optarg);
710ab129e90SDaniel Mrzyglod 			if (ret < 0) {
711ab129e90SDaniel Mrzyglod 				print_usage(prgname);
712ab129e90SDaniel Mrzyglod 				return -1;
713ab129e90SDaniel Mrzyglod 			}
714ab129e90SDaniel Mrzyglod 
715ab129e90SDaniel Mrzyglod 			ptp_data.kernel_time_set = ret;
716ab129e90SDaniel Mrzyglod 			break;
717ab129e90SDaniel Mrzyglod 
718ab129e90SDaniel Mrzyglod 		default:
719ab129e90SDaniel Mrzyglod 			print_usage(prgname);
720ab129e90SDaniel Mrzyglod 			return -1;
721ab129e90SDaniel Mrzyglod 		}
722ab129e90SDaniel Mrzyglod 	}
723ab129e90SDaniel Mrzyglod 
724ab129e90SDaniel Mrzyglod 	argv[optind-1] = prgname;
725ab129e90SDaniel Mrzyglod 
7269d5ca532SKeith Wiles 	optind = 1; /* Reset getopt lib. */
727ab129e90SDaniel Mrzyglod 
728ab129e90SDaniel Mrzyglod 	return 0;
729ab129e90SDaniel Mrzyglod }
730ab129e90SDaniel Mrzyglod 
731ab129e90SDaniel Mrzyglod /*
732ab129e90SDaniel Mrzyglod  * The main function, which does initialization and calls the per-lcore
733ab129e90SDaniel Mrzyglod  * functions.
734ab129e90SDaniel Mrzyglod  */
735ab129e90SDaniel Mrzyglod int
736ab129e90SDaniel Mrzyglod main(int argc, char *argv[])
737ab129e90SDaniel Mrzyglod {
738ab129e90SDaniel Mrzyglod 	unsigned nb_ports;
739ab129e90SDaniel Mrzyglod 
74047523597SZhiyong Yang 	uint16_t portid;
741ab129e90SDaniel Mrzyglod 
7429a212dc0SConor Fogarty 	/* Initialize the Environment Abstraction Layer (EAL). 8< */
743ab129e90SDaniel Mrzyglod 	int ret = rte_eal_init(argc, argv);
744ab129e90SDaniel Mrzyglod 
745ab129e90SDaniel Mrzyglod 	if (ret < 0)
746ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
7479a212dc0SConor Fogarty 	/* >8 End of initialization of EAL. */
748ab129e90SDaniel Mrzyglod 
749ab129e90SDaniel Mrzyglod 	memset(&ptp_data, '\0', sizeof(struct ptpv2_data_slave_ordinary));
750ab129e90SDaniel Mrzyglod 
7519a212dc0SConor Fogarty 	/* Parse specific arguments. 8< */
752ab129e90SDaniel Mrzyglod 	argc -= ret;
753ab129e90SDaniel Mrzyglod 	argv += ret;
754ab129e90SDaniel Mrzyglod 
755ab129e90SDaniel Mrzyglod 	ret = ptp_parse_args(argc, argv);
756ab129e90SDaniel Mrzyglod 	if (ret < 0)
757ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
7589a212dc0SConor Fogarty 	/* >8 End of parsing specific arguments. */
759ab129e90SDaniel Mrzyglod 
760ab129e90SDaniel Mrzyglod 	/* Check that there is an even number of ports to send/receive on. */
761d9a42a69SThomas Monjalon 	nb_ports = rte_eth_dev_count_avail();
762ab129e90SDaniel Mrzyglod 
7639a212dc0SConor Fogarty 	/* Creates a new mempool in memory to hold the mbufs. 8< */
764ab129e90SDaniel Mrzyglod 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
765ab129e90SDaniel Mrzyglod 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
7669a212dc0SConor Fogarty 	/* >8 End of a new mempool in memory to hold the mbufs. */
767ab129e90SDaniel Mrzyglod 
768ab129e90SDaniel Mrzyglod 	if (mbuf_pool == NULL)
769ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
770ab129e90SDaniel Mrzyglod 
7719a212dc0SConor Fogarty 	/* Initialize all ports. 8< */
7728728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
773ab129e90SDaniel Mrzyglod 		if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
774ab129e90SDaniel Mrzyglod 			if (port_init(portid, mbuf_pool) == 0) {
775ab129e90SDaniel Mrzyglod 				ptp_enabled_ports[ptp_enabled_port_nb] = portid;
776ab129e90SDaniel Mrzyglod 				ptp_enabled_port_nb++;
777ab129e90SDaniel Mrzyglod 			} else {
778ab129e90SDaniel Mrzyglod 				rte_exit(EXIT_FAILURE,
779ab129e90SDaniel Mrzyglod 					 "Cannot init port %"PRIu8 "\n",
780ab129e90SDaniel Mrzyglod 					 portid);
781ab129e90SDaniel Mrzyglod 			}
782ab129e90SDaniel Mrzyglod 		} else
783ab129e90SDaniel Mrzyglod 			printf("Skipping disabled port %u\n", portid);
784ab129e90SDaniel Mrzyglod 	}
7859a212dc0SConor Fogarty 	/* >8 End of initialization of all ports. */
786ab129e90SDaniel Mrzyglod 
787ab129e90SDaniel Mrzyglod 	if (ptp_enabled_port_nb == 0) {
788ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE,
789ab129e90SDaniel Mrzyglod 			"All available ports are disabled."
790ab129e90SDaniel Mrzyglod 			" Please set portmask.\n");
791ab129e90SDaniel Mrzyglod 	}
792ab129e90SDaniel Mrzyglod 
793ab129e90SDaniel Mrzyglod 	if (rte_lcore_count() > 1)
794ab129e90SDaniel Mrzyglod 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
795ab129e90SDaniel Mrzyglod 
796cb056611SStephen Hemminger 	/* Call lcore_main on the main core only. */
797ab129e90SDaniel Mrzyglod 	lcore_main();
798ab129e90SDaniel Mrzyglod 
79910aa3757SChengchang Tang 	/* clean up the EAL */
80010aa3757SChengchang Tang 	rte_eal_cleanup();
80110aa3757SChengchang Tang 
802ab129e90SDaniel Mrzyglod 	return 0;
803ab129e90SDaniel Mrzyglod }
804