xref: /dpdk/examples/ptpclient/ptpclient.c (revision 8badf48d2100aa4f16b48f8006774febb65e47f3)
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>
23*8badf48dSRahul Bhansali #include <signal.h>
24*8badf48dSRahul Bhansali 
25*8badf48dSRahul 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. */
59ab129e90SDaniel Mrzyglod struct tstamp {
60ab129e90SDaniel Mrzyglod 	uint16_t   sec_msb;
61ab129e90SDaniel Mrzyglod 	uint32_t   sec_lsb;
62ab129e90SDaniel Mrzyglod 	uint32_t   ns;
63ef5baf34SThomas Monjalon }  __rte_packed;
64ab129e90SDaniel Mrzyglod 
65ab129e90SDaniel Mrzyglod struct clock_id {
66ab129e90SDaniel Mrzyglod 	uint8_t id[8];
67ab129e90SDaniel Mrzyglod };
68ab129e90SDaniel Mrzyglod 
69ab129e90SDaniel Mrzyglod struct port_id {
70ab129e90SDaniel Mrzyglod 	struct clock_id        clock_id;
71ab129e90SDaniel Mrzyglod 	uint16_t               port_number;
72ef5baf34SThomas Monjalon }  __rte_packed;
73ab129e90SDaniel Mrzyglod 
74ab129e90SDaniel Mrzyglod struct 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;
87ef5baf34SThomas Monjalon } __rte_packed;
88ab129e90SDaniel Mrzyglod 
89ab129e90SDaniel Mrzyglod struct sync_msg {
90ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
91ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
92ef5baf34SThomas Monjalon } __rte_packed;
93ab129e90SDaniel Mrzyglod 
94ab129e90SDaniel Mrzyglod struct follow_up_msg {
95ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
96ab129e90SDaniel Mrzyglod 	struct tstamp       precise_origin_tstamp;
97013b4c52SBruce Richardson 	uint8_t             suffix[];
98ef5baf34SThomas Monjalon } __rte_packed;
99ab129e90SDaniel Mrzyglod 
100ab129e90SDaniel Mrzyglod struct delay_req_msg {
101ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
102ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
103ef5baf34SThomas Monjalon } __rte_packed;
104ab129e90SDaniel Mrzyglod 
105ab129e90SDaniel Mrzyglod struct 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[];
110ef5baf34SThomas Monjalon } __rte_packed;
111ab129e90SDaniel Mrzyglod 
112ab129e90SDaniel Mrzyglod struct ptp_message {
113ab129e90SDaniel Mrzyglod 	union {
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;
119ef5baf34SThomas Monjalon 	} __rte_packed;
120ab129e90SDaniel Mrzyglod };
121ab129e90SDaniel Mrzyglod 
122ab129e90SDaniel Mrzyglod struct ptpv2_data_slave_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;
129ab129e90SDaniel Mrzyglod 	struct clock_id master_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 
140ab129e90SDaniel Mrzyglod static struct ptpv2_data_slave_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
269ab129e90SDaniel Mrzyglod print_clock_info(struct ptpv2_data_slave_ordinary *ptp_data)
270ab129e90SDaniel Mrzyglod {
271ab129e90SDaniel Mrzyglod 	int64_t nsec;
272ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
273ab129e90SDaniel Mrzyglod 
274ab129e90SDaniel Mrzyglod 	printf("Master Clock id: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
275ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[0],
276ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[1],
277ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[2],
278ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[3],
279ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[4],
280ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[5],
281ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[6],
282ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[7]);
283ab129e90SDaniel Mrzyglod 
284ab129e90SDaniel Mrzyglod 	printf("\nT2 - Slave  Clock.  %lds %ldns",
285ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_sec),
286ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_nsec));
287ab129e90SDaniel Mrzyglod 
288ab129e90SDaniel Mrzyglod 	printf("\nT1 - Master Clock.  %lds %ldns ",
289ab129e90SDaniel Mrzyglod 			ptp_data->tstamp1.tv_sec,
290ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp1.tv_nsec));
291ab129e90SDaniel Mrzyglod 
292ab129e90SDaniel Mrzyglod 	printf("\nT3 - Slave  Clock.  %lds %ldns",
293ab129e90SDaniel Mrzyglod 			ptp_data->tstamp3.tv_sec,
294ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp3.tv_nsec));
295ab129e90SDaniel Mrzyglod 
296ab129e90SDaniel Mrzyglod 	printf("\nT4 - Master Clock.  %lds %ldns ",
297ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec,
298ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp4.tv_nsec));
299ab129e90SDaniel Mrzyglod 
300ab129e90SDaniel Mrzyglod 	printf("\nDelta between master and slave clocks:%"PRId64"ns\n",
301ab129e90SDaniel Mrzyglod 			ptp_data->delta);
302ab129e90SDaniel Mrzyglod 
303ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
304ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data->current_ptp_port, &net_time);
305ab129e90SDaniel Mrzyglod 
306ab129e90SDaniel Mrzyglod 	time_t ts = net_time.tv_sec;
307ab129e90SDaniel Mrzyglod 
308ab129e90SDaniel Mrzyglod 	printf("\n\nComparison between Linux kernel Time and PTP:");
309ab129e90SDaniel Mrzyglod 
310ab129e90SDaniel Mrzyglod 	printf("\nCurrent PTP Time: %.24s %.9ld ns",
311ab129e90SDaniel Mrzyglod 			ctime(&ts), net_time.tv_nsec);
312ab129e90SDaniel Mrzyglod 
313ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
314ab129e90SDaniel Mrzyglod 			(int64_t)timespec64_to_ns(&sys_time);
315ab129e90SDaniel Mrzyglod 	ptp_data->new_adj = ns_to_timeval(nsec);
316ab129e90SDaniel Mrzyglod 
317ab129e90SDaniel Mrzyglod 	gettimeofday(&ptp_data->new_adj, NULL);
318ab129e90SDaniel Mrzyglod 
319ab129e90SDaniel Mrzyglod 	time_t tp = ptp_data->new_adj.tv_sec;
320ab129e90SDaniel Mrzyglod 
321ab129e90SDaniel Mrzyglod 	printf("\nCurrent SYS Time: %.24s %.6ld ns",
322ab129e90SDaniel Mrzyglod 				ctime(&tp), ptp_data->new_adj.tv_usec);
323ab129e90SDaniel Mrzyglod 
324ab129e90SDaniel Mrzyglod 	printf("\nDelta between PTP and Linux Kernel time:%"PRId64"ns\n",
325ab129e90SDaniel Mrzyglod 				nsec);
326ab129e90SDaniel Mrzyglod 
327ab129e90SDaniel Mrzyglod 	printf("[Ctrl+C to quit]\n");
328ab129e90SDaniel Mrzyglod 
329ab129e90SDaniel Mrzyglod 	/* Clear screen and put cursor in column 1, row 1 */
330ab129e90SDaniel Mrzyglod 	printf("\033[2J\033[1;1H");
331ab129e90SDaniel Mrzyglod }
332ab129e90SDaniel Mrzyglod 
333ab129e90SDaniel Mrzyglod static int64_t
334ab129e90SDaniel Mrzyglod delta_eval(struct ptpv2_data_slave_ordinary *ptp_data)
335ab129e90SDaniel Mrzyglod {
336ab129e90SDaniel Mrzyglod 	int64_t delta;
337ab129e90SDaniel Mrzyglod 	uint64_t t1 = 0;
338ab129e90SDaniel Mrzyglod 	uint64_t t2 = 0;
339ab129e90SDaniel Mrzyglod 	uint64_t t3 = 0;
340ab129e90SDaniel Mrzyglod 	uint64_t t4 = 0;
341ab129e90SDaniel Mrzyglod 
342ab129e90SDaniel Mrzyglod 	t1 = timespec64_to_ns(&ptp_data->tstamp1);
343ab129e90SDaniel Mrzyglod 	t2 = timespec64_to_ns(&ptp_data->tstamp2);
344ab129e90SDaniel Mrzyglod 	t3 = timespec64_to_ns(&ptp_data->tstamp3);
345ab129e90SDaniel Mrzyglod 	t4 = timespec64_to_ns(&ptp_data->tstamp4);
346ab129e90SDaniel Mrzyglod 
347ab129e90SDaniel Mrzyglod 	delta = -((int64_t)((t2 - t1) - (t4 - t3))) / 2;
348ab129e90SDaniel Mrzyglod 
349ab129e90SDaniel Mrzyglod 	return delta;
350ab129e90SDaniel Mrzyglod }
351ab129e90SDaniel Mrzyglod 
352ab129e90SDaniel Mrzyglod /*
353ab129e90SDaniel Mrzyglod  * Parse the PTP SYNC message.
354ab129e90SDaniel Mrzyglod  */
355ab129e90SDaniel Mrzyglod static void
356ab129e90SDaniel Mrzyglod parse_sync(struct ptpv2_data_slave_ordinary *ptp_data, uint16_t rx_tstamp_idx)
357ab129e90SDaniel Mrzyglod {
358ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
359ab129e90SDaniel Mrzyglod 
360cebcefbaSStephen Hemminger 	ptp_hdr = rte_pktmbuf_mtod_offset(ptp_data->m, struct ptp_header *,
361cebcefbaSStephen Hemminger 					  sizeof(struct rte_ether_hdr));
362ab129e90SDaniel Mrzyglod 	ptp_data->seqID_SYNC = rte_be_to_cpu_16(ptp_hdr->seq_id);
363ab129e90SDaniel Mrzyglod 
364ab129e90SDaniel Mrzyglod 	if (ptp_data->ptpset == 0) {
365ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->master_clock_id,
366ab129e90SDaniel Mrzyglod 				&ptp_hdr->source_port_id.clock_id,
367ab129e90SDaniel Mrzyglod 				sizeof(struct clock_id));
368ab129e90SDaniel Mrzyglod 		ptp_data->ptpset = 1;
369ab129e90SDaniel Mrzyglod 	}
370ab129e90SDaniel Mrzyglod 
371ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_hdr->source_port_id.clock_id,
372ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
373ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) == 0) {
374ab129e90SDaniel Mrzyglod 
375ab129e90SDaniel Mrzyglod 		if (ptp_data->ptpset == 1)
376ab129e90SDaniel Mrzyglod 			rte_eth_timesync_read_rx_timestamp(ptp_data->portid,
377ab129e90SDaniel Mrzyglod 					&ptp_data->tstamp2, rx_tstamp_idx);
378ab129e90SDaniel Mrzyglod 	}
379ab129e90SDaniel Mrzyglod 
380ab129e90SDaniel Mrzyglod }
381ab129e90SDaniel Mrzyglod 
382ab129e90SDaniel Mrzyglod /*
383cb056611SStephen Hemminger  * Parse the PTP FOLLOWUP message and send DELAY_REQ to the main clock.
384ab129e90SDaniel Mrzyglod  */
385ab129e90SDaniel Mrzyglod static void
386ab129e90SDaniel Mrzyglod parse_fup(struct ptpv2_data_slave_ordinary *ptp_data)
387ab129e90SDaniel Mrzyglod {
3886d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
38970febdcfSIgor Romanov 	struct rte_ether_addr eth_addr;
390ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
391ab129e90SDaniel Mrzyglod 	struct clock_id *client_clkid;
392ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
39321ba4d57SVanshika Shukla 	struct delay_req_msg *req_msg;
394ab129e90SDaniel Mrzyglod 	struct rte_mbuf *created_pkt;
395ab129e90SDaniel Mrzyglod 	struct tstamp *origin_tstamp;
3966d13ea8eSOlivier Matz 	struct rte_ether_addr eth_multicast = ether_multicast;
397ab129e90SDaniel Mrzyglod 	size_t pkt_size;
398ab129e90SDaniel Mrzyglod 	int wait_us;
399ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
40070febdcfSIgor Romanov 	int ret;
401ab129e90SDaniel Mrzyglod 
4026d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
403cebcefbaSStephen Hemminger 	ptp_hdr = rte_pktmbuf_mtod_offset(m, struct ptp_header *,
404cebcefbaSStephen Hemminger 					  sizeof(struct rte_ether_hdr));
405ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->master_clock_id,
406ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
407ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) != 0)
408ab129e90SDaniel Mrzyglod 		return;
409ab129e90SDaniel Mrzyglod 
410ab129e90SDaniel Mrzyglod 	ptp_data->seqID_FOLLOWUP = rte_be_to_cpu_16(ptp_hdr->seq_id);
411cebcefbaSStephen Hemminger 	ptp_msg = rte_pktmbuf_mtod_offset(m, struct ptp_message *,
4126d13ea8eSOlivier Matz 					  sizeof(struct rte_ether_hdr));
413ab129e90SDaniel Mrzyglod 
414ab129e90SDaniel Mrzyglod 	origin_tstamp = &ptp_msg->follow_up.precise_origin_tstamp;
415ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_nsec = ntohl(origin_tstamp->ns);
416ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_sec =
417ab129e90SDaniel Mrzyglod 		((uint64_t)ntohl(origin_tstamp->sec_lsb)) |
418ab129e90SDaniel Mrzyglod 		(((uint64_t)ntohs(origin_tstamp->sec_msb)) << 32);
419ab129e90SDaniel Mrzyglod 
420ab129e90SDaniel Mrzyglod 	if (ptp_data->seqID_FOLLOWUP == ptp_data->seqID_SYNC) {
42170febdcfSIgor Romanov 		ret = rte_eth_macaddr_get(ptp_data->portid, &eth_addr);
42270febdcfSIgor Romanov 		if (ret != 0) {
42370febdcfSIgor Romanov 			printf("\nCore %u: port %u failed to get MAC address: %s\n",
42470febdcfSIgor Romanov 				rte_lcore_id(), ptp_data->portid,
42570febdcfSIgor Romanov 				rte_strerror(-ret));
42670febdcfSIgor Romanov 			return;
42770febdcfSIgor Romanov 		}
428ab129e90SDaniel Mrzyglod 
429ab129e90SDaniel Mrzyglod 		created_pkt = rte_pktmbuf_alloc(mbuf_pool);
4306d13ea8eSOlivier Matz 		pkt_size = sizeof(struct rte_ether_hdr) +
43121ba4d57SVanshika Shukla 			sizeof(struct delay_req_msg);
43221ba4d57SVanshika Shukla 
43321ba4d57SVanshika Shukla 		if (rte_pktmbuf_append(created_pkt, pkt_size) == NULL) {
43421ba4d57SVanshika Shukla 			rte_pktmbuf_free(created_pkt);
43521ba4d57SVanshika Shukla 			return;
43621ba4d57SVanshika Shukla 		}
437ab129e90SDaniel Mrzyglod 		created_pkt->data_len = pkt_size;
438ab129e90SDaniel Mrzyglod 		created_pkt->pkt_len = pkt_size;
4396d13ea8eSOlivier Matz 		eth_hdr = rte_pktmbuf_mtod(created_pkt, struct rte_ether_hdr *);
44004d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_addr, &eth_hdr->src_addr);
441ab129e90SDaniel Mrzyglod 
442ab129e90SDaniel Mrzyglod 		/* Set multicast address 01-1B-19-00-00-00. */
44304d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_multicast, &eth_hdr->dst_addr);
444ab129e90SDaniel Mrzyglod 
445ab129e90SDaniel Mrzyglod 		eth_hdr->ether_type = htons(PTP_PROTOCOL);
44621ba4d57SVanshika Shukla 		req_msg = rte_pktmbuf_mtod_offset(created_pkt,
44721ba4d57SVanshika Shukla 			struct delay_req_msg *, sizeof(struct
44821ba4d57SVanshika Shukla 			rte_ether_hdr));
449ab129e90SDaniel Mrzyglod 
45021ba4d57SVanshika Shukla 		req_msg->hdr.seq_id = htons(ptp_data->seqID_SYNC);
45121ba4d57SVanshika Shukla 		req_msg->hdr.msg_type = DELAY_REQ;
45221ba4d57SVanshika Shukla 		req_msg->hdr.ver = 2;
45321ba4d57SVanshika Shukla 		req_msg->hdr.control = 1;
45421ba4d57SVanshika Shukla 		req_msg->hdr.log_message_interval = 127;
45521ba4d57SVanshika Shukla 		req_msg->hdr.message_length =
456376aa383SHarman Kalra 			htons(sizeof(struct delay_req_msg));
45721ba4d57SVanshika Shukla 		req_msg->hdr.domain_number = ptp_hdr->domain_number;
458ab129e90SDaniel Mrzyglod 
459ab129e90SDaniel Mrzyglod 		/* Set up clock id. */
460ab129e90SDaniel Mrzyglod 		client_clkid =
46121ba4d57SVanshika Shukla 			&req_msg->hdr.source_port_id.clock_id;
462ab129e90SDaniel Mrzyglod 
46304d43857SDmitry Kozlyuk 		client_clkid->id[0] = eth_hdr->src_addr.addr_bytes[0];
46404d43857SDmitry Kozlyuk 		client_clkid->id[1] = eth_hdr->src_addr.addr_bytes[1];
46504d43857SDmitry Kozlyuk 		client_clkid->id[2] = eth_hdr->src_addr.addr_bytes[2];
466ab129e90SDaniel Mrzyglod 		client_clkid->id[3] = 0xFF;
467ab129e90SDaniel Mrzyglod 		client_clkid->id[4] = 0xFE;
46804d43857SDmitry Kozlyuk 		client_clkid->id[5] = eth_hdr->src_addr.addr_bytes[3];
46904d43857SDmitry Kozlyuk 		client_clkid->id[6] = eth_hdr->src_addr.addr_bytes[4];
47004d43857SDmitry Kozlyuk 		client_clkid->id[7] = eth_hdr->src_addr.addr_bytes[5];
471ab129e90SDaniel Mrzyglod 
472ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->client_clock_id,
473ab129e90SDaniel Mrzyglod 			   client_clkid,
474ab129e90SDaniel Mrzyglod 			   sizeof(struct clock_id));
475ab129e90SDaniel Mrzyglod 
476ab129e90SDaniel Mrzyglod 		/* Enable flag for hardware timestamping. */
477daa02b5cSOlivier Matz 		created_pkt->ol_flags |= RTE_MBUF_F_TX_IEEE1588_TMST;
478ab129e90SDaniel Mrzyglod 
479ab129e90SDaniel Mrzyglod 		/*Read value from NIC to prevent latching with old value. */
480ab129e90SDaniel Mrzyglod 		rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
481ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3);
482ab129e90SDaniel Mrzyglod 
483ab129e90SDaniel Mrzyglod 		/* Transmit the packet. */
484ab129e90SDaniel Mrzyglod 		rte_eth_tx_burst(ptp_data->portid, 0, &created_pkt, 1);
485ab129e90SDaniel Mrzyglod 
486ab129e90SDaniel Mrzyglod 		wait_us = 0;
487ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_nsec = 0;
488ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_sec = 0;
489ab129e90SDaniel Mrzyglod 
490ab129e90SDaniel Mrzyglod 		/* Wait at least 1 us to read TX timestamp. */
491ab129e90SDaniel Mrzyglod 		while ((rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
492ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3) < 0) && (wait_us < 1000)) {
493ab129e90SDaniel Mrzyglod 			rte_delay_us(1);
494ab129e90SDaniel Mrzyglod 			wait_us++;
495ab129e90SDaniel Mrzyglod 		}
496ab129e90SDaniel Mrzyglod 	}
497ab129e90SDaniel Mrzyglod }
498ab129e90SDaniel Mrzyglod 
499ab129e90SDaniel Mrzyglod /*
500ab129e90SDaniel Mrzyglod  * Update the kernel time with the difference between it and the current NIC
501ab129e90SDaniel Mrzyglod  * time.
502ab129e90SDaniel Mrzyglod  */
503ab129e90SDaniel Mrzyglod static inline void
504ab129e90SDaniel Mrzyglod update_kernel_time(void)
505ab129e90SDaniel Mrzyglod {
506ab129e90SDaniel Mrzyglod 	int64_t nsec;
507ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
508ab129e90SDaniel Mrzyglod 
509ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
510ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data.current_ptp_port, &net_time);
511ab129e90SDaniel Mrzyglod 
512ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
513ab129e90SDaniel Mrzyglod 	       (int64_t)timespec64_to_ns(&sys_time);
514ab129e90SDaniel Mrzyglod 
515ab129e90SDaniel Mrzyglod 	ptp_data.new_adj = ns_to_timeval(nsec);
516ab129e90SDaniel Mrzyglod 
517ab129e90SDaniel Mrzyglod 	/*
518ab129e90SDaniel Mrzyglod 	 * If difference between kernel time and system time in NIC is too big
519ab129e90SDaniel Mrzyglod 	 * (more than +/- 20 microseconds), use clock_settime to set directly
520ab129e90SDaniel Mrzyglod 	 * the kernel time, as adjtime is better for small adjustments (takes
521ab129e90SDaniel Mrzyglod 	 * longer to adjust the time).
522ab129e90SDaniel Mrzyglod 	 */
523ab129e90SDaniel Mrzyglod 
524ab129e90SDaniel Mrzyglod 	if (nsec > KERNEL_TIME_ADJUST_LIMIT || nsec < -KERNEL_TIME_ADJUST_LIMIT)
525ab129e90SDaniel Mrzyglod 		clock_settime(CLOCK_REALTIME, &net_time);
526ab129e90SDaniel Mrzyglod 	else
527ab129e90SDaniel Mrzyglod 		adjtime(&ptp_data.new_adj, 0);
528ab129e90SDaniel Mrzyglod 
529ab129e90SDaniel Mrzyglod 
530ab129e90SDaniel Mrzyglod }
531ab129e90SDaniel Mrzyglod 
532ab129e90SDaniel Mrzyglod /*
533ab129e90SDaniel Mrzyglod  * Parse the DELAY_RESP message.
534ab129e90SDaniel Mrzyglod  */
535ab129e90SDaniel Mrzyglod static void
536ab129e90SDaniel Mrzyglod parse_drsp(struct ptpv2_data_slave_ordinary *ptp_data)
537ab129e90SDaniel Mrzyglod {
538ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
539ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
540ab129e90SDaniel Mrzyglod 	struct tstamp *rx_tstamp;
541ab129e90SDaniel Mrzyglod 	uint16_t seq_id;
542ab129e90SDaniel Mrzyglod 
543cebcefbaSStephen Hemminger 	ptp_msg = rte_pktmbuf_mtod_offset(m, struct ptp_message *,
5446d13ea8eSOlivier Matz 					  sizeof(struct rte_ether_hdr));
545ab129e90SDaniel Mrzyglod 	seq_id = rte_be_to_cpu_16(ptp_msg->delay_resp.hdr.seq_id);
546ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->client_clock_id,
547ab129e90SDaniel Mrzyglod 		   &ptp_msg->delay_resp.req_port_id.clock_id,
548ab129e90SDaniel Mrzyglod 		   sizeof(struct clock_id)) == 0) {
549ab129e90SDaniel Mrzyglod 		if (seq_id == ptp_data->seqID_FOLLOWUP) {
550ab129e90SDaniel Mrzyglod 			rx_tstamp = &ptp_msg->delay_resp.rx_tstamp;
551ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_nsec = ntohl(rx_tstamp->ns);
552ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec =
553ab129e90SDaniel Mrzyglod 				((uint64_t)ntohl(rx_tstamp->sec_lsb)) |
554ab129e90SDaniel Mrzyglod 				(((uint64_t)ntohs(rx_tstamp->sec_msb)) << 32);
555ab129e90SDaniel Mrzyglod 
556ab129e90SDaniel Mrzyglod 			/* Evaluate the delta for adjustment. */
557ab129e90SDaniel Mrzyglod 			ptp_data->delta = delta_eval(ptp_data);
558ab129e90SDaniel Mrzyglod 
559ab129e90SDaniel Mrzyglod 			rte_eth_timesync_adjust_time(ptp_data->portid,
560ab129e90SDaniel Mrzyglod 						     ptp_data->delta);
561ab129e90SDaniel Mrzyglod 
562ab129e90SDaniel Mrzyglod 			ptp_data->current_ptp_port = ptp_data->portid;
563ab129e90SDaniel Mrzyglod 
564ab129e90SDaniel Mrzyglod 			/* Update kernel time if enabled in app parameters. */
565ab129e90SDaniel Mrzyglod 			if (ptp_data->kernel_time_set == 1)
566ab129e90SDaniel Mrzyglod 				update_kernel_time();
567ab129e90SDaniel Mrzyglod 
568ab129e90SDaniel Mrzyglod 
569ab129e90SDaniel Mrzyglod 
570ab129e90SDaniel Mrzyglod 		}
571ab129e90SDaniel Mrzyglod 	}
572ab129e90SDaniel Mrzyglod }
573ab129e90SDaniel Mrzyglod 
574ab129e90SDaniel Mrzyglod /* This function processes PTP packets, implementing slave PTP IEEE1588 L2
575ab129e90SDaniel Mrzyglod  * functionality.
576ab129e90SDaniel Mrzyglod  */
5779a212dc0SConor Fogarty 
5789a212dc0SConor Fogarty /* Parse ptp frames. 8< */
579ab129e90SDaniel Mrzyglod static void
58047523597SZhiyong Yang parse_ptp_frames(uint16_t portid, struct rte_mbuf *m) {
581ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
5826d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
583ab129e90SDaniel Mrzyglod 	uint16_t eth_type;
584ab129e90SDaniel Mrzyglod 
5856d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
586ab129e90SDaniel Mrzyglod 	eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
587ab129e90SDaniel Mrzyglod 
588ab129e90SDaniel Mrzyglod 	if (eth_type == PTP_PROTOCOL) {
589ab129e90SDaniel Mrzyglod 		ptp_data.m = m;
590ab129e90SDaniel Mrzyglod 		ptp_data.portid = portid;
591cebcefbaSStephen Hemminger 		ptp_hdr = rte_pktmbuf_mtod_offset(m, struct ptp_header *,
592cebcefbaSStephen Hemminger 						  sizeof(struct rte_ether_hdr));
593ab129e90SDaniel Mrzyglod 
594ab129e90SDaniel Mrzyglod 		switch (ptp_hdr->msg_type) {
595ab129e90SDaniel Mrzyglod 		case SYNC:
596ab129e90SDaniel Mrzyglod 			parse_sync(&ptp_data, m->timesync);
597ab129e90SDaniel Mrzyglod 			break;
598ab129e90SDaniel Mrzyglod 		case FOLLOW_UP:
599ab129e90SDaniel Mrzyglod 			parse_fup(&ptp_data);
600ab129e90SDaniel Mrzyglod 			break;
601ab129e90SDaniel Mrzyglod 		case DELAY_RESP:
602ab129e90SDaniel Mrzyglod 			parse_drsp(&ptp_data);
603ab129e90SDaniel Mrzyglod 			print_clock_info(&ptp_data);
604ab129e90SDaniel Mrzyglod 			break;
605ab129e90SDaniel Mrzyglod 		default:
606ab129e90SDaniel Mrzyglod 			break;
607ab129e90SDaniel Mrzyglod 		}
608ab129e90SDaniel Mrzyglod 	}
609ab129e90SDaniel Mrzyglod }
6109a212dc0SConor Fogarty /* >8 End of function processes PTP packets. */
611ab129e90SDaniel Mrzyglod 
612ab129e90SDaniel Mrzyglod /*
613ab129e90SDaniel Mrzyglod  * The lcore main. This is the main thread that does the work, reading from an
614ab129e90SDaniel Mrzyglod  * input port and writing to an output port.
615ab129e90SDaniel Mrzyglod  */
616*8badf48dSRahul Bhansali static void
617ab129e90SDaniel Mrzyglod lcore_main(void)
618ab129e90SDaniel Mrzyglod {
61947523597SZhiyong Yang 	uint16_t portid;
620ab129e90SDaniel Mrzyglod 	unsigned nb_rx;
621ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
622ab129e90SDaniel Mrzyglod 
623ab129e90SDaniel Mrzyglod 	printf("\nCore %u Waiting for SYNC packets. [Ctrl+C to quit]\n",
624ab129e90SDaniel Mrzyglod 			rte_lcore_id());
625ab129e90SDaniel Mrzyglod 
626ab129e90SDaniel Mrzyglod 	/* Run until the application is quit or killed. */
627ab129e90SDaniel Mrzyglod 
628*8badf48dSRahul Bhansali 	while (!force_quit) {
6299a212dc0SConor Fogarty 		/* Read packet from RX queues. 8< */
630ab129e90SDaniel Mrzyglod 		for (portid = 0; portid < ptp_enabled_port_nb; portid++) {
631ab129e90SDaniel Mrzyglod 
632ab129e90SDaniel Mrzyglod 			portid = ptp_enabled_ports[portid];
633ab129e90SDaniel Mrzyglod 			nb_rx = rte_eth_rx_burst(portid, 0, &m, 1);
634ab129e90SDaniel Mrzyglod 
635ab129e90SDaniel Mrzyglod 			if (likely(nb_rx == 0))
636ab129e90SDaniel Mrzyglod 				continue;
637ab129e90SDaniel Mrzyglod 
6389a212dc0SConor Fogarty 			/* Packet is parsed to determine which type. 8< */
639daa02b5cSOlivier Matz 			if (m->ol_flags & RTE_MBUF_F_RX_IEEE1588_PTP)
640ab129e90SDaniel Mrzyglod 				parse_ptp_frames(portid, m);
6419a212dc0SConor Fogarty 			/* >8 End of packet is parsed to determine which type. */
642ab129e90SDaniel Mrzyglod 
643ab129e90SDaniel Mrzyglod 			rte_pktmbuf_free(m);
644ab129e90SDaniel Mrzyglod 		}
6459a212dc0SConor Fogarty 		/* >8 End of read packets from RX queues. */
646ab129e90SDaniel Mrzyglod 	}
647ab129e90SDaniel Mrzyglod }
648ab129e90SDaniel Mrzyglod 
649ab129e90SDaniel Mrzyglod static void
650ab129e90SDaniel Mrzyglod print_usage(const char *prgname)
651ab129e90SDaniel Mrzyglod {
652ab129e90SDaniel Mrzyglod 	printf("%s [EAL options] -- -p PORTMASK -T VALUE\n"
653ab129e90SDaniel Mrzyglod 		" -T VALUE: 0 - Disable, 1 - Enable Linux Clock"
654ab129e90SDaniel Mrzyglod 		" Synchronization (0 default)\n"
655ab129e90SDaniel Mrzyglod 		" -p PORTMASK: hexadecimal bitmask of ports to configure\n",
656ab129e90SDaniel Mrzyglod 		prgname);
657ab129e90SDaniel Mrzyglod }
658ab129e90SDaniel Mrzyglod 
659ab129e90SDaniel Mrzyglod static int
660ab129e90SDaniel Mrzyglod ptp_parse_portmask(const char *portmask)
661ab129e90SDaniel Mrzyglod {
662ab129e90SDaniel Mrzyglod 	char *end = NULL;
663ab129e90SDaniel Mrzyglod 	unsigned long pm;
664ab129e90SDaniel Mrzyglod 
665ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
666ab129e90SDaniel Mrzyglod 	pm = strtoul(portmask, &end, 16);
667ab129e90SDaniel Mrzyglod 
668ab129e90SDaniel Mrzyglod 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
669ce6b8c31SSarosh Arif 		return 0;
670ab129e90SDaniel Mrzyglod 
671ab129e90SDaniel Mrzyglod 	return pm;
672ab129e90SDaniel Mrzyglod }
673ab129e90SDaniel Mrzyglod 
674ab129e90SDaniel Mrzyglod static int
675ab129e90SDaniel Mrzyglod parse_ptp_kernel(const char *param)
676ab129e90SDaniel Mrzyglod {
677ab129e90SDaniel Mrzyglod 	char *end = NULL;
678ab129e90SDaniel Mrzyglod 	unsigned long pm;
679ab129e90SDaniel Mrzyglod 
680ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
681ab129e90SDaniel Mrzyglod 	pm = strtoul(param, &end, 16);
682ab129e90SDaniel Mrzyglod 
683ab129e90SDaniel Mrzyglod 	if ((param[0] == '\0') || (end == NULL) || (*end != '\0'))
684ab129e90SDaniel Mrzyglod 		return -1;
685ab129e90SDaniel Mrzyglod 	if (pm == 0)
686ab129e90SDaniel Mrzyglod 		return 0;
687ab129e90SDaniel Mrzyglod 
688ab129e90SDaniel Mrzyglod 	return 1;
689ab129e90SDaniel Mrzyglod }
690ab129e90SDaniel Mrzyglod 
691ab129e90SDaniel Mrzyglod /* Parse the commandline arguments. */
692ab129e90SDaniel Mrzyglod static int
693ab129e90SDaniel Mrzyglod ptp_parse_args(int argc, char **argv)
694ab129e90SDaniel Mrzyglod {
695ab129e90SDaniel Mrzyglod 	int opt, ret;
696ab129e90SDaniel Mrzyglod 	char **argvopt;
697ab129e90SDaniel Mrzyglod 	int option_index;
698ab129e90SDaniel Mrzyglod 	char *prgname = argv[0];
699ab129e90SDaniel Mrzyglod 	static struct option lgopts[] = { {NULL, 0, 0, 0} };
700ab129e90SDaniel Mrzyglod 
701ab129e90SDaniel Mrzyglod 	argvopt = argv;
702ab129e90SDaniel Mrzyglod 
703ab129e90SDaniel Mrzyglod 	while ((opt = getopt_long(argc, argvopt, "p:T:",
704ab129e90SDaniel Mrzyglod 				  lgopts, &option_index)) != EOF) {
705ab129e90SDaniel Mrzyglod 
706ab129e90SDaniel Mrzyglod 		switch (opt) {
707ab129e90SDaniel Mrzyglod 
708ab129e90SDaniel Mrzyglod 		/* Portmask. */
709ab129e90SDaniel Mrzyglod 		case 'p':
710ab129e90SDaniel Mrzyglod 			ptp_enabled_port_mask = ptp_parse_portmask(optarg);
711ab129e90SDaniel Mrzyglod 			if (ptp_enabled_port_mask == 0) {
712ab129e90SDaniel Mrzyglod 				printf("invalid portmask\n");
713ab129e90SDaniel Mrzyglod 				print_usage(prgname);
714ab129e90SDaniel Mrzyglod 				return -1;
715ab129e90SDaniel Mrzyglod 			}
716ab129e90SDaniel Mrzyglod 			break;
717ab129e90SDaniel Mrzyglod 		/* Time synchronization. */
718ab129e90SDaniel Mrzyglod 		case 'T':
719ab129e90SDaniel Mrzyglod 			ret = parse_ptp_kernel(optarg);
720ab129e90SDaniel Mrzyglod 			if (ret < 0) {
721ab129e90SDaniel Mrzyglod 				print_usage(prgname);
722ab129e90SDaniel Mrzyglod 				return -1;
723ab129e90SDaniel Mrzyglod 			}
724ab129e90SDaniel Mrzyglod 
725ab129e90SDaniel Mrzyglod 			ptp_data.kernel_time_set = ret;
726ab129e90SDaniel Mrzyglod 			break;
727ab129e90SDaniel Mrzyglod 
728ab129e90SDaniel Mrzyglod 		default:
729ab129e90SDaniel Mrzyglod 			print_usage(prgname);
730ab129e90SDaniel Mrzyglod 			return -1;
731ab129e90SDaniel Mrzyglod 		}
732ab129e90SDaniel Mrzyglod 	}
733ab129e90SDaniel Mrzyglod 
734ab129e90SDaniel Mrzyglod 	argv[optind-1] = prgname;
735ab129e90SDaniel Mrzyglod 
7369d5ca532SKeith Wiles 	optind = 1; /* Reset getopt lib. */
737ab129e90SDaniel Mrzyglod 
738ab129e90SDaniel Mrzyglod 	return 0;
739ab129e90SDaniel Mrzyglod }
740ab129e90SDaniel Mrzyglod 
741*8badf48dSRahul Bhansali static void
742*8badf48dSRahul Bhansali signal_handler(int signum)
743*8badf48dSRahul Bhansali {
744*8badf48dSRahul Bhansali 	if (signum == SIGINT || signum == SIGTERM)
745*8badf48dSRahul Bhansali 		force_quit = true;
746*8badf48dSRahul Bhansali }
747*8badf48dSRahul Bhansali 
748ab129e90SDaniel Mrzyglod /*
749ab129e90SDaniel Mrzyglod  * The main function, which does initialization and calls the per-lcore
750ab129e90SDaniel Mrzyglod  * functions.
751ab129e90SDaniel Mrzyglod  */
752ab129e90SDaniel Mrzyglod int
753ab129e90SDaniel Mrzyglod main(int argc, char *argv[])
754ab129e90SDaniel Mrzyglod {
755ab129e90SDaniel Mrzyglod 	unsigned nb_ports;
756ab129e90SDaniel Mrzyglod 
75747523597SZhiyong Yang 	uint16_t portid;
758ab129e90SDaniel Mrzyglod 
7599a212dc0SConor Fogarty 	/* Initialize the Environment Abstraction Layer (EAL). 8< */
760ab129e90SDaniel Mrzyglod 	int ret = rte_eal_init(argc, argv);
761ab129e90SDaniel Mrzyglod 
762ab129e90SDaniel Mrzyglod 	if (ret < 0)
763ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
7649a212dc0SConor Fogarty 	/* >8 End of initialization of EAL. */
765ab129e90SDaniel Mrzyglod 
766ab129e90SDaniel Mrzyglod 	memset(&ptp_data, '\0', sizeof(struct ptpv2_data_slave_ordinary));
767ab129e90SDaniel Mrzyglod 
7689a212dc0SConor Fogarty 	/* Parse specific arguments. 8< */
769ab129e90SDaniel Mrzyglod 	argc -= ret;
770ab129e90SDaniel Mrzyglod 	argv += ret;
771ab129e90SDaniel Mrzyglod 
772*8badf48dSRahul Bhansali 	force_quit = false;
773*8badf48dSRahul Bhansali 	signal(SIGINT, signal_handler);
774*8badf48dSRahul Bhansali 	signal(SIGTERM, signal_handler);
775*8badf48dSRahul Bhansali 
776ab129e90SDaniel Mrzyglod 	ret = ptp_parse_args(argc, argv);
777ab129e90SDaniel Mrzyglod 	if (ret < 0)
778ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
7799a212dc0SConor Fogarty 	/* >8 End of parsing specific arguments. */
780ab129e90SDaniel Mrzyglod 
781ab129e90SDaniel Mrzyglod 	/* Check that there is an even number of ports to send/receive on. */
782d9a42a69SThomas Monjalon 	nb_ports = rte_eth_dev_count_avail();
783ab129e90SDaniel Mrzyglod 
7849a212dc0SConor Fogarty 	/* Creates a new mempool in memory to hold the mbufs. 8< */
785ab129e90SDaniel Mrzyglod 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
786ab129e90SDaniel Mrzyglod 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
7879a212dc0SConor Fogarty 	/* >8 End of a new mempool in memory to hold the mbufs. */
788ab129e90SDaniel Mrzyglod 
789ab129e90SDaniel Mrzyglod 	if (mbuf_pool == NULL)
790ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
791ab129e90SDaniel Mrzyglod 
7929a212dc0SConor Fogarty 	/* Initialize all ports. 8< */
7938728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
794ab129e90SDaniel Mrzyglod 		if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
795ab129e90SDaniel Mrzyglod 			if (port_init(portid, mbuf_pool) == 0) {
796ab129e90SDaniel Mrzyglod 				ptp_enabled_ports[ptp_enabled_port_nb] = portid;
797ab129e90SDaniel Mrzyglod 				ptp_enabled_port_nb++;
798ab129e90SDaniel Mrzyglod 			} else {
799ab129e90SDaniel Mrzyglod 				rte_exit(EXIT_FAILURE,
800ab129e90SDaniel Mrzyglod 					 "Cannot init port %"PRIu8 "\n",
801ab129e90SDaniel Mrzyglod 					 portid);
802ab129e90SDaniel Mrzyglod 			}
803ab129e90SDaniel Mrzyglod 		} else
804ab129e90SDaniel Mrzyglod 			printf("Skipping disabled port %u\n", portid);
805ab129e90SDaniel Mrzyglod 	}
8069a212dc0SConor Fogarty 	/* >8 End of initialization of all ports. */
807ab129e90SDaniel Mrzyglod 
808ab129e90SDaniel Mrzyglod 	if (ptp_enabled_port_nb == 0) {
809ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE,
810ab129e90SDaniel Mrzyglod 			"All available ports are disabled."
811ab129e90SDaniel Mrzyglod 			" Please set portmask.\n");
812ab129e90SDaniel Mrzyglod 	}
813ab129e90SDaniel Mrzyglod 
814ab129e90SDaniel Mrzyglod 	if (rte_lcore_count() > 1)
815ab129e90SDaniel Mrzyglod 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
816ab129e90SDaniel Mrzyglod 
817cb056611SStephen Hemminger 	/* Call lcore_main on the main core only. */
818ab129e90SDaniel Mrzyglod 	lcore_main();
819ab129e90SDaniel Mrzyglod 
820*8badf48dSRahul Bhansali 	RTE_ETH_FOREACH_DEV(portid) {
821*8badf48dSRahul Bhansali 		if ((ptp_enabled_port_mask & (1 << portid)) == 0)
822*8badf48dSRahul Bhansali 			continue;
823*8badf48dSRahul Bhansali 
824*8badf48dSRahul Bhansali 		/* Disable timesync timestamping for the Ethernet device */
825*8badf48dSRahul Bhansali 		rte_eth_timesync_disable(portid);
826*8badf48dSRahul Bhansali 
827*8badf48dSRahul Bhansali 		ret = rte_eth_dev_stop(portid);
828*8badf48dSRahul Bhansali 		if (ret != 0)
829*8badf48dSRahul Bhansali 			printf("rte_eth_dev_stop: err=%d, port=%d\n", ret, portid);
830*8badf48dSRahul Bhansali 
831*8badf48dSRahul Bhansali 		rte_eth_dev_close(portid);
832*8badf48dSRahul Bhansali 	}
833*8badf48dSRahul Bhansali 
83410aa3757SChengchang Tang 	/* clean up the EAL */
83510aa3757SChengchang Tang 	rte_eal_cleanup();
83610aa3757SChengchang Tang 
837ab129e90SDaniel Mrzyglod 	return 0;
838ab129e90SDaniel Mrzyglod }
839