xref: /dpdk/examples/ptpclient/ptpclient.c (revision 089e5ed727a15da2729cfee9b63533dd120bd04c)
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 
50ab129e90SDaniel Mrzyglod static const struct rte_eth_conf port_conf_default = {
51b960219bSShahaf Shuler 	.rxmode = {
5235b2d13fSOlivier Matz 		.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
53b960219bSShahaf Shuler 	},
54ab129e90SDaniel Mrzyglod };
55ab129e90SDaniel Mrzyglod 
566d13ea8eSOlivier Matz static const struct rte_ether_addr ether_multicast = {
57ab129e90SDaniel Mrzyglod 	.addr_bytes = {0x01, 0x1b, 0x19, 0x0, 0x0, 0x0}
58ab129e90SDaniel Mrzyglod };
59ab129e90SDaniel Mrzyglod 
60ab129e90SDaniel Mrzyglod /* Structs used for PTP handling. */
61ab129e90SDaniel Mrzyglod struct tstamp {
62ab129e90SDaniel Mrzyglod 	uint16_t   sec_msb;
63ab129e90SDaniel Mrzyglod 	uint32_t   sec_lsb;
64ab129e90SDaniel Mrzyglod 	uint32_t   ns;
65ab129e90SDaniel Mrzyglod }  __attribute__((packed));
66ab129e90SDaniel Mrzyglod 
67ab129e90SDaniel Mrzyglod struct clock_id {
68ab129e90SDaniel Mrzyglod 	uint8_t id[8];
69ab129e90SDaniel Mrzyglod };
70ab129e90SDaniel Mrzyglod 
71ab129e90SDaniel Mrzyglod struct port_id {
72ab129e90SDaniel Mrzyglod 	struct clock_id        clock_id;
73ab129e90SDaniel Mrzyglod 	uint16_t               port_number;
74ab129e90SDaniel Mrzyglod }  __attribute__((packed));
75ab129e90SDaniel Mrzyglod 
76ab129e90SDaniel Mrzyglod struct ptp_header {
77ab129e90SDaniel Mrzyglod 	uint8_t              msg_type;
78ab129e90SDaniel Mrzyglod 	uint8_t              ver;
79ab129e90SDaniel Mrzyglod 	uint16_t             message_length;
80ab129e90SDaniel Mrzyglod 	uint8_t              domain_number;
81ab129e90SDaniel Mrzyglod 	uint8_t              reserved1;
82ab129e90SDaniel Mrzyglod 	uint8_t              flag_field[2];
83ab129e90SDaniel Mrzyglod 	int64_t              correction;
84ab129e90SDaniel Mrzyglod 	uint32_t             reserved2;
85ab129e90SDaniel Mrzyglod 	struct port_id       source_port_id;
86ab129e90SDaniel Mrzyglod 	uint16_t             seq_id;
87ab129e90SDaniel Mrzyglod 	uint8_t              control;
88ab129e90SDaniel Mrzyglod 	int8_t               log_message_interval;
89ab129e90SDaniel Mrzyglod } __attribute__((packed));
90ab129e90SDaniel Mrzyglod 
91ab129e90SDaniel Mrzyglod struct sync_msg {
92ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
93ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
94ab129e90SDaniel Mrzyglod } __attribute__((packed));
95ab129e90SDaniel Mrzyglod 
96ab129e90SDaniel Mrzyglod struct follow_up_msg {
97ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
98ab129e90SDaniel Mrzyglod 	struct tstamp       precise_origin_tstamp;
99ab129e90SDaniel Mrzyglod 	uint8_t             suffix[0];
100ab129e90SDaniel Mrzyglod } __attribute__((packed));
101ab129e90SDaniel Mrzyglod 
102ab129e90SDaniel Mrzyglod struct delay_req_msg {
103ab129e90SDaniel Mrzyglod 	struct ptp_header   hdr;
104ab129e90SDaniel Mrzyglod 	struct tstamp       origin_tstamp;
105ab129e90SDaniel Mrzyglod } __attribute__((packed));
106ab129e90SDaniel Mrzyglod 
107ab129e90SDaniel Mrzyglod struct delay_resp_msg {
108ab129e90SDaniel Mrzyglod 	struct ptp_header    hdr;
109ab129e90SDaniel Mrzyglod 	struct tstamp        rx_tstamp;
110ab129e90SDaniel Mrzyglod 	struct port_id       req_port_id;
111ab129e90SDaniel Mrzyglod 	uint8_t              suffix[0];
112ab129e90SDaniel Mrzyglod } __attribute__((packed));
113ab129e90SDaniel Mrzyglod 
114ab129e90SDaniel Mrzyglod struct ptp_message {
115ab129e90SDaniel Mrzyglod 	union {
116ab129e90SDaniel Mrzyglod 		struct ptp_header          header;
117ab129e90SDaniel Mrzyglod 		struct sync_msg            sync;
118ab129e90SDaniel Mrzyglod 		struct delay_req_msg       delay_req;
119ab129e90SDaniel Mrzyglod 		struct follow_up_msg       follow_up;
120ab129e90SDaniel Mrzyglod 		struct delay_resp_msg      delay_resp;
121ab129e90SDaniel Mrzyglod 	} __attribute__((packed));
122ab129e90SDaniel Mrzyglod };
123ab129e90SDaniel Mrzyglod 
124ab129e90SDaniel Mrzyglod struct ptpv2_data_slave_ordinary {
125ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
126ab129e90SDaniel Mrzyglod 	struct timespec tstamp1;
127ab129e90SDaniel Mrzyglod 	struct timespec tstamp2;
128ab129e90SDaniel Mrzyglod 	struct timespec tstamp3;
129ab129e90SDaniel Mrzyglod 	struct timespec tstamp4;
130ab129e90SDaniel Mrzyglod 	struct clock_id client_clock_id;
131ab129e90SDaniel Mrzyglod 	struct clock_id master_clock_id;
132ab129e90SDaniel Mrzyglod 	struct timeval new_adj;
133ab129e90SDaniel Mrzyglod 	int64_t delta;
134f8244c63SZhiyong Yang 	uint16_t portid;
135ab129e90SDaniel Mrzyglod 	uint16_t seqID_SYNC;
136ab129e90SDaniel Mrzyglod 	uint16_t seqID_FOLLOWUP;
137ab129e90SDaniel Mrzyglod 	uint8_t ptpset;
138ab129e90SDaniel Mrzyglod 	uint8_t kernel_time_set;
139f8244c63SZhiyong Yang 	uint16_t current_ptp_port;
140ab129e90SDaniel Mrzyglod };
141ab129e90SDaniel Mrzyglod 
142ab129e90SDaniel Mrzyglod static struct ptpv2_data_slave_ordinary ptp_data;
143ab129e90SDaniel Mrzyglod 
144ab129e90SDaniel Mrzyglod static inline uint64_t timespec64_to_ns(const struct timespec *ts)
145ab129e90SDaniel Mrzyglod {
146ab129e90SDaniel Mrzyglod 	return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
147ab129e90SDaniel Mrzyglod }
148ab129e90SDaniel Mrzyglod 
149ab129e90SDaniel Mrzyglod static struct timeval
150ab129e90SDaniel Mrzyglod ns_to_timeval(int64_t nsec)
151ab129e90SDaniel Mrzyglod {
152ab129e90SDaniel Mrzyglod 	struct timespec t_spec = {0, 0};
153ab129e90SDaniel Mrzyglod 	struct timeval t_eval = {0, 0};
154ab129e90SDaniel Mrzyglod 	int32_t rem;
155ab129e90SDaniel Mrzyglod 
156ab129e90SDaniel Mrzyglod 	if (nsec == 0)
157ab129e90SDaniel Mrzyglod 		return t_eval;
158ab129e90SDaniel Mrzyglod 	rem = nsec % NSEC_PER_SEC;
159ab129e90SDaniel Mrzyglod 	t_spec.tv_sec = nsec / NSEC_PER_SEC;
160ab129e90SDaniel Mrzyglod 
161ab129e90SDaniel Mrzyglod 	if (rem < 0) {
162ab129e90SDaniel Mrzyglod 		t_spec.tv_sec--;
163ab129e90SDaniel Mrzyglod 		rem += NSEC_PER_SEC;
164ab129e90SDaniel Mrzyglod 	}
165ab129e90SDaniel Mrzyglod 
166ab129e90SDaniel Mrzyglod 	t_spec.tv_nsec = rem;
167ab129e90SDaniel Mrzyglod 	t_eval.tv_sec = t_spec.tv_sec;
168ab129e90SDaniel Mrzyglod 	t_eval.tv_usec = t_spec.tv_nsec / 1000;
169ab129e90SDaniel Mrzyglod 
170ab129e90SDaniel Mrzyglod 	return t_eval;
171ab129e90SDaniel Mrzyglod }
172ab129e90SDaniel Mrzyglod 
173ab129e90SDaniel Mrzyglod /*
174ab129e90SDaniel Mrzyglod  * Initializes a given port using global settings and with the RX buffers
175ab129e90SDaniel Mrzyglod  * coming from the mbuf_pool passed as a parameter.
176ab129e90SDaniel Mrzyglod  */
177ab129e90SDaniel Mrzyglod static inline int
17847523597SZhiyong Yang port_init(uint16_t port, struct rte_mempool *mbuf_pool)
179ab129e90SDaniel Mrzyglod {
180ab129e90SDaniel Mrzyglod 	struct rte_eth_dev_info dev_info;
181ab129e90SDaniel Mrzyglod 	struct rte_eth_conf port_conf = port_conf_default;
182ab129e90SDaniel Mrzyglod 	const uint16_t rx_rings = 1;
183ab129e90SDaniel Mrzyglod 	const uint16_t tx_rings = 1;
184ab129e90SDaniel Mrzyglod 	int retval;
185ab129e90SDaniel Mrzyglod 	uint16_t q;
18660efb44fSRoman Zhukov 	uint16_t nb_rxd = RX_RING_SIZE;
18760efb44fSRoman Zhukov 	uint16_t nb_txd = TX_RING_SIZE;
188ab129e90SDaniel Mrzyglod 
189a9dbe180SThomas Monjalon 	if (!rte_eth_dev_is_valid_port(port))
190ab129e90SDaniel Mrzyglod 		return -1;
191ab129e90SDaniel Mrzyglod 
192*089e5ed7SIvan Ilchenko 	retval = rte_eth_dev_info_get(port, &dev_info);
193*089e5ed7SIvan Ilchenko 	if (retval != 0) {
194*089e5ed7SIvan Ilchenko 		printf("Error during getting device (port %u) info: %s\n",
195*089e5ed7SIvan Ilchenko 				port, strerror(-retval));
196*089e5ed7SIvan Ilchenko 
197*089e5ed7SIvan Ilchenko 		return retval;
198*089e5ed7SIvan Ilchenko 	}
199*089e5ed7SIvan Ilchenko 
200b960219bSShahaf Shuler 	if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
201b960219bSShahaf Shuler 		port_conf.txmode.offloads |=
202b960219bSShahaf Shuler 			DEV_TX_OFFLOAD_MBUF_FAST_FREE;
2030625a29fSPablo de Lara 	/* Force full Tx path in the driver, required for IEEE1588 */
2040625a29fSPablo de Lara 	port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;
205b960219bSShahaf Shuler 
206ab129e90SDaniel Mrzyglod 	/* Configure the Ethernet device. */
207ab129e90SDaniel Mrzyglod 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
208ab129e90SDaniel Mrzyglod 	if (retval != 0)
209ab129e90SDaniel Mrzyglod 		return retval;
210ab129e90SDaniel Mrzyglod 
21160efb44fSRoman Zhukov 	retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
21260efb44fSRoman Zhukov 	if (retval != 0)
21360efb44fSRoman Zhukov 		return retval;
21460efb44fSRoman Zhukov 
215ab129e90SDaniel Mrzyglod 	/* Allocate and set up 1 RX queue per Ethernet port. */
216ab129e90SDaniel Mrzyglod 	for (q = 0; q < rx_rings; q++) {
21760efb44fSRoman Zhukov 		retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
218ab129e90SDaniel Mrzyglod 				rte_eth_dev_socket_id(port), NULL, mbuf_pool);
219ab129e90SDaniel Mrzyglod 
220ab129e90SDaniel Mrzyglod 		if (retval < 0)
221ab129e90SDaniel Mrzyglod 			return retval;
222ab129e90SDaniel Mrzyglod 	}
223ab129e90SDaniel Mrzyglod 
224ab129e90SDaniel Mrzyglod 	/* Allocate and set up 1 TX queue per Ethernet port. */
225ab129e90SDaniel Mrzyglod 	for (q = 0; q < tx_rings; q++) {
226ab129e90SDaniel Mrzyglod 		struct rte_eth_txconf *txconf;
227ab129e90SDaniel Mrzyglod 
228ab129e90SDaniel Mrzyglod 		txconf = &dev_info.default_txconf;
229b960219bSShahaf Shuler 		txconf->offloads = port_conf.txmode.offloads;
230ab129e90SDaniel Mrzyglod 
23160efb44fSRoman Zhukov 		retval = rte_eth_tx_queue_setup(port, q, nb_txd,
232ab129e90SDaniel Mrzyglod 				rte_eth_dev_socket_id(port), txconf);
233ab129e90SDaniel Mrzyglod 		if (retval < 0)
234ab129e90SDaniel Mrzyglod 			return retval;
235ab129e90SDaniel Mrzyglod 	}
236ab129e90SDaniel Mrzyglod 
237ab129e90SDaniel Mrzyglod 	/* Start the Ethernet port. */
238ab129e90SDaniel Mrzyglod 	retval = rte_eth_dev_start(port);
239ab129e90SDaniel Mrzyglod 	if (retval < 0)
240ab129e90SDaniel Mrzyglod 		return retval;
241ab129e90SDaniel Mrzyglod 
242ab129e90SDaniel Mrzyglod 	/* Enable timesync timestamping for the Ethernet device */
243376aa383SHarman Kalra 	retval = rte_eth_timesync_enable(port);
244376aa383SHarman Kalra 	if (retval < 0) {
245376aa383SHarman Kalra 		printf("Timesync enable failed: %d\n", retval);
246376aa383SHarman Kalra 		return retval;
247376aa383SHarman Kalra 	}
248ab129e90SDaniel Mrzyglod 
249ab129e90SDaniel Mrzyglod 	/* Enable RX in promiscuous mode for the Ethernet device. */
250ab129e90SDaniel Mrzyglod 	rte_eth_promiscuous_enable(port);
251ab129e90SDaniel Mrzyglod 
252ab129e90SDaniel Mrzyglod 	return 0;
253ab129e90SDaniel Mrzyglod }
254ab129e90SDaniel Mrzyglod 
255ab129e90SDaniel Mrzyglod static void
256ab129e90SDaniel Mrzyglod print_clock_info(struct ptpv2_data_slave_ordinary *ptp_data)
257ab129e90SDaniel Mrzyglod {
258ab129e90SDaniel Mrzyglod 	int64_t nsec;
259ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
260ab129e90SDaniel Mrzyglod 
261ab129e90SDaniel Mrzyglod 	printf("Master Clock id: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
262ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[0],
263ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[1],
264ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[2],
265ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[3],
266ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[4],
267ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[5],
268ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[6],
269ab129e90SDaniel Mrzyglod 		ptp_data->master_clock_id.id[7]);
270ab129e90SDaniel Mrzyglod 
271ab129e90SDaniel Mrzyglod 	printf("\nT2 - Slave  Clock.  %lds %ldns",
272ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_sec),
273ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp2.tv_nsec));
274ab129e90SDaniel Mrzyglod 
275ab129e90SDaniel Mrzyglod 	printf("\nT1 - Master Clock.  %lds %ldns ",
276ab129e90SDaniel Mrzyglod 			ptp_data->tstamp1.tv_sec,
277ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp1.tv_nsec));
278ab129e90SDaniel Mrzyglod 
279ab129e90SDaniel Mrzyglod 	printf("\nT3 - Slave  Clock.  %lds %ldns",
280ab129e90SDaniel Mrzyglod 			ptp_data->tstamp3.tv_sec,
281ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp3.tv_nsec));
282ab129e90SDaniel Mrzyglod 
283ab129e90SDaniel Mrzyglod 	printf("\nT4 - Master Clock.  %lds %ldns ",
284ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec,
285ab129e90SDaniel Mrzyglod 			(ptp_data->tstamp4.tv_nsec));
286ab129e90SDaniel Mrzyglod 
287ab129e90SDaniel Mrzyglod 	printf("\nDelta between master and slave clocks:%"PRId64"ns\n",
288ab129e90SDaniel Mrzyglod 			ptp_data->delta);
289ab129e90SDaniel Mrzyglod 
290ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
291ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data->current_ptp_port, &net_time);
292ab129e90SDaniel Mrzyglod 
293ab129e90SDaniel Mrzyglod 	time_t ts = net_time.tv_sec;
294ab129e90SDaniel Mrzyglod 
295ab129e90SDaniel Mrzyglod 	printf("\n\nComparison between Linux kernel Time and PTP:");
296ab129e90SDaniel Mrzyglod 
297ab129e90SDaniel Mrzyglod 	printf("\nCurrent PTP Time: %.24s %.9ld ns",
298ab129e90SDaniel Mrzyglod 			ctime(&ts), net_time.tv_nsec);
299ab129e90SDaniel Mrzyglod 
300ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
301ab129e90SDaniel Mrzyglod 			(int64_t)timespec64_to_ns(&sys_time);
302ab129e90SDaniel Mrzyglod 	ptp_data->new_adj = ns_to_timeval(nsec);
303ab129e90SDaniel Mrzyglod 
304ab129e90SDaniel Mrzyglod 	gettimeofday(&ptp_data->new_adj, NULL);
305ab129e90SDaniel Mrzyglod 
306ab129e90SDaniel Mrzyglod 	time_t tp = ptp_data->new_adj.tv_sec;
307ab129e90SDaniel Mrzyglod 
308ab129e90SDaniel Mrzyglod 	printf("\nCurrent SYS Time: %.24s %.6ld ns",
309ab129e90SDaniel Mrzyglod 				ctime(&tp), ptp_data->new_adj.tv_usec);
310ab129e90SDaniel Mrzyglod 
311ab129e90SDaniel Mrzyglod 	printf("\nDelta between PTP and Linux Kernel time:%"PRId64"ns\n",
312ab129e90SDaniel Mrzyglod 				nsec);
313ab129e90SDaniel Mrzyglod 
314ab129e90SDaniel Mrzyglod 	printf("[Ctrl+C to quit]\n");
315ab129e90SDaniel Mrzyglod 
316ab129e90SDaniel Mrzyglod 	/* Clear screen and put cursor in column 1, row 1 */
317ab129e90SDaniel Mrzyglod 	printf("\033[2J\033[1;1H");
318ab129e90SDaniel Mrzyglod }
319ab129e90SDaniel Mrzyglod 
320ab129e90SDaniel Mrzyglod static int64_t
321ab129e90SDaniel Mrzyglod delta_eval(struct ptpv2_data_slave_ordinary *ptp_data)
322ab129e90SDaniel Mrzyglod {
323ab129e90SDaniel Mrzyglod 	int64_t delta;
324ab129e90SDaniel Mrzyglod 	uint64_t t1 = 0;
325ab129e90SDaniel Mrzyglod 	uint64_t t2 = 0;
326ab129e90SDaniel Mrzyglod 	uint64_t t3 = 0;
327ab129e90SDaniel Mrzyglod 	uint64_t t4 = 0;
328ab129e90SDaniel Mrzyglod 
329ab129e90SDaniel Mrzyglod 	t1 = timespec64_to_ns(&ptp_data->tstamp1);
330ab129e90SDaniel Mrzyglod 	t2 = timespec64_to_ns(&ptp_data->tstamp2);
331ab129e90SDaniel Mrzyglod 	t3 = timespec64_to_ns(&ptp_data->tstamp3);
332ab129e90SDaniel Mrzyglod 	t4 = timespec64_to_ns(&ptp_data->tstamp4);
333ab129e90SDaniel Mrzyglod 
334ab129e90SDaniel Mrzyglod 	delta = -((int64_t)((t2 - t1) - (t4 - t3))) / 2;
335ab129e90SDaniel Mrzyglod 
336ab129e90SDaniel Mrzyglod 	return delta;
337ab129e90SDaniel Mrzyglod }
338ab129e90SDaniel Mrzyglod 
339ab129e90SDaniel Mrzyglod /*
340ab129e90SDaniel Mrzyglod  * Parse the PTP SYNC message.
341ab129e90SDaniel Mrzyglod  */
342ab129e90SDaniel Mrzyglod static void
343ab129e90SDaniel Mrzyglod parse_sync(struct ptpv2_data_slave_ordinary *ptp_data, uint16_t rx_tstamp_idx)
344ab129e90SDaniel Mrzyglod {
345ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
346ab129e90SDaniel Mrzyglod 
347ab129e90SDaniel Mrzyglod 	ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(ptp_data->m, char *)
3486d13ea8eSOlivier Matz 			+ sizeof(struct rte_ether_hdr));
349ab129e90SDaniel Mrzyglod 	ptp_data->seqID_SYNC = rte_be_to_cpu_16(ptp_hdr->seq_id);
350ab129e90SDaniel Mrzyglod 
351ab129e90SDaniel Mrzyglod 	if (ptp_data->ptpset == 0) {
352ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->master_clock_id,
353ab129e90SDaniel Mrzyglod 				&ptp_hdr->source_port_id.clock_id,
354ab129e90SDaniel Mrzyglod 				sizeof(struct clock_id));
355ab129e90SDaniel Mrzyglod 		ptp_data->ptpset = 1;
356ab129e90SDaniel Mrzyglod 	}
357ab129e90SDaniel Mrzyglod 
358ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_hdr->source_port_id.clock_id,
359ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
360ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) == 0) {
361ab129e90SDaniel Mrzyglod 
362ab129e90SDaniel Mrzyglod 		if (ptp_data->ptpset == 1)
363ab129e90SDaniel Mrzyglod 			rte_eth_timesync_read_rx_timestamp(ptp_data->portid,
364ab129e90SDaniel Mrzyglod 					&ptp_data->tstamp2, rx_tstamp_idx);
365ab129e90SDaniel Mrzyglod 	}
366ab129e90SDaniel Mrzyglod 
367ab129e90SDaniel Mrzyglod }
368ab129e90SDaniel Mrzyglod 
369ab129e90SDaniel Mrzyglod /*
370ab129e90SDaniel Mrzyglod  * Parse the PTP FOLLOWUP message and send DELAY_REQ to the master clock.
371ab129e90SDaniel Mrzyglod  */
372ab129e90SDaniel Mrzyglod static void
373ab129e90SDaniel Mrzyglod parse_fup(struct ptpv2_data_slave_ordinary *ptp_data)
374ab129e90SDaniel Mrzyglod {
3756d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
376ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
377ab129e90SDaniel Mrzyglod 	struct clock_id *client_clkid;
378ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
379ab129e90SDaniel Mrzyglod 	struct rte_mbuf *created_pkt;
380ab129e90SDaniel Mrzyglod 	struct tstamp *origin_tstamp;
3816d13ea8eSOlivier Matz 	struct rte_ether_addr eth_multicast = ether_multicast;
382ab129e90SDaniel Mrzyglod 	size_t pkt_size;
383ab129e90SDaniel Mrzyglod 	int wait_us;
384ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
385ab129e90SDaniel Mrzyglod 
3866d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
387ab129e90SDaniel Mrzyglod 	ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(m, char *)
3886d13ea8eSOlivier Matz 			+ sizeof(struct rte_ether_hdr));
389ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->master_clock_id,
390ab129e90SDaniel Mrzyglod 			&ptp_hdr->source_port_id.clock_id,
391ab129e90SDaniel Mrzyglod 			sizeof(struct clock_id)) != 0)
392ab129e90SDaniel Mrzyglod 		return;
393ab129e90SDaniel Mrzyglod 
394ab129e90SDaniel Mrzyglod 	ptp_data->seqID_FOLLOWUP = rte_be_to_cpu_16(ptp_hdr->seq_id);
395ab129e90SDaniel Mrzyglod 	ptp_msg = (struct ptp_message *) (rte_pktmbuf_mtod(m, char *) +
3966d13ea8eSOlivier Matz 					  sizeof(struct rte_ether_hdr));
397ab129e90SDaniel Mrzyglod 
398ab129e90SDaniel Mrzyglod 	origin_tstamp = &ptp_msg->follow_up.precise_origin_tstamp;
399ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_nsec = ntohl(origin_tstamp->ns);
400ab129e90SDaniel Mrzyglod 	ptp_data->tstamp1.tv_sec =
401ab129e90SDaniel Mrzyglod 		((uint64_t)ntohl(origin_tstamp->sec_lsb)) |
402ab129e90SDaniel Mrzyglod 		(((uint64_t)ntohs(origin_tstamp->sec_msb)) << 32);
403ab129e90SDaniel Mrzyglod 
404ab129e90SDaniel Mrzyglod 	if (ptp_data->seqID_FOLLOWUP == ptp_data->seqID_SYNC) {
405ab129e90SDaniel Mrzyglod 
406ab129e90SDaniel Mrzyglod 		created_pkt = rte_pktmbuf_alloc(mbuf_pool);
4076d13ea8eSOlivier Matz 		pkt_size = sizeof(struct rte_ether_hdr) +
408ab129e90SDaniel Mrzyglod 			sizeof(struct ptp_message);
409ab129e90SDaniel Mrzyglod 		created_pkt->data_len = pkt_size;
410ab129e90SDaniel Mrzyglod 		created_pkt->pkt_len = pkt_size;
4116d13ea8eSOlivier Matz 		eth_hdr = rte_pktmbuf_mtod(created_pkt, struct rte_ether_hdr *);
412ab129e90SDaniel Mrzyglod 		rte_eth_macaddr_get(ptp_data->portid, &eth_hdr->s_addr);
413ab129e90SDaniel Mrzyglod 
414ab129e90SDaniel Mrzyglod 		/* Set multicast address 01-1B-19-00-00-00. */
415538da7a1SOlivier Matz 		rte_ether_addr_copy(&eth_multicast, &eth_hdr->d_addr);
416ab129e90SDaniel Mrzyglod 
417ab129e90SDaniel Mrzyglod 		eth_hdr->ether_type = htons(PTP_PROTOCOL);
418ab129e90SDaniel Mrzyglod 		ptp_msg = (struct ptp_message *)
419ab129e90SDaniel Mrzyglod 			(rte_pktmbuf_mtod(created_pkt, char *) +
4206d13ea8eSOlivier Matz 			sizeof(struct rte_ether_hdr));
421ab129e90SDaniel Mrzyglod 
422ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.seq_id = htons(ptp_data->seqID_SYNC);
423ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.msg_type = DELAY_REQ;
424ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.ver = 2;
425ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.control = 1;
426ab129e90SDaniel Mrzyglod 		ptp_msg->delay_req.hdr.log_message_interval = 127;
427376aa383SHarman Kalra 		ptp_msg->delay_req.hdr.message_length =
428376aa383SHarman Kalra 			htons(sizeof(struct delay_req_msg));
429376aa383SHarman Kalra 		ptp_msg->delay_req.hdr.domain_number = ptp_hdr->domain_number;
430ab129e90SDaniel Mrzyglod 
431ab129e90SDaniel Mrzyglod 		/* Set up clock id. */
432ab129e90SDaniel Mrzyglod 		client_clkid =
433ab129e90SDaniel Mrzyglod 			&ptp_msg->delay_req.hdr.source_port_id.clock_id;
434ab129e90SDaniel Mrzyglod 
435ab129e90SDaniel Mrzyglod 		client_clkid->id[0] = eth_hdr->s_addr.addr_bytes[0];
436ab129e90SDaniel Mrzyglod 		client_clkid->id[1] = eth_hdr->s_addr.addr_bytes[1];
437ab129e90SDaniel Mrzyglod 		client_clkid->id[2] = eth_hdr->s_addr.addr_bytes[2];
438ab129e90SDaniel Mrzyglod 		client_clkid->id[3] = 0xFF;
439ab129e90SDaniel Mrzyglod 		client_clkid->id[4] = 0xFE;
440ab129e90SDaniel Mrzyglod 		client_clkid->id[5] = eth_hdr->s_addr.addr_bytes[3];
441ab129e90SDaniel Mrzyglod 		client_clkid->id[6] = eth_hdr->s_addr.addr_bytes[4];
442ab129e90SDaniel Mrzyglod 		client_clkid->id[7] = eth_hdr->s_addr.addr_bytes[5];
443ab129e90SDaniel Mrzyglod 
444ab129e90SDaniel Mrzyglod 		rte_memcpy(&ptp_data->client_clock_id,
445ab129e90SDaniel Mrzyglod 			   client_clkid,
446ab129e90SDaniel Mrzyglod 			   sizeof(struct clock_id));
447ab129e90SDaniel Mrzyglod 
448ab129e90SDaniel Mrzyglod 		/* Enable flag for hardware timestamping. */
449ab129e90SDaniel Mrzyglod 		created_pkt->ol_flags |= PKT_TX_IEEE1588_TMST;
450ab129e90SDaniel Mrzyglod 
451ab129e90SDaniel Mrzyglod 		/*Read value from NIC to prevent latching with old value. */
452ab129e90SDaniel Mrzyglod 		rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
453ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3);
454ab129e90SDaniel Mrzyglod 
455ab129e90SDaniel Mrzyglod 		/* Transmit the packet. */
456ab129e90SDaniel Mrzyglod 		rte_eth_tx_burst(ptp_data->portid, 0, &created_pkt, 1);
457ab129e90SDaniel Mrzyglod 
458ab129e90SDaniel Mrzyglod 		wait_us = 0;
459ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_nsec = 0;
460ab129e90SDaniel Mrzyglod 		ptp_data->tstamp3.tv_sec = 0;
461ab129e90SDaniel Mrzyglod 
462ab129e90SDaniel Mrzyglod 		/* Wait at least 1 us to read TX timestamp. */
463ab129e90SDaniel Mrzyglod 		while ((rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
464ab129e90SDaniel Mrzyglod 				&ptp_data->tstamp3) < 0) && (wait_us < 1000)) {
465ab129e90SDaniel Mrzyglod 			rte_delay_us(1);
466ab129e90SDaniel Mrzyglod 			wait_us++;
467ab129e90SDaniel Mrzyglod 		}
468ab129e90SDaniel Mrzyglod 	}
469ab129e90SDaniel Mrzyglod }
470ab129e90SDaniel Mrzyglod 
471ab129e90SDaniel Mrzyglod /*
472ab129e90SDaniel Mrzyglod  * Update the kernel time with the difference between it and the current NIC
473ab129e90SDaniel Mrzyglod  * time.
474ab129e90SDaniel Mrzyglod  */
475ab129e90SDaniel Mrzyglod static inline void
476ab129e90SDaniel Mrzyglod update_kernel_time(void)
477ab129e90SDaniel Mrzyglod {
478ab129e90SDaniel Mrzyglod 	int64_t nsec;
479ab129e90SDaniel Mrzyglod 	struct timespec net_time, sys_time;
480ab129e90SDaniel Mrzyglod 
481ab129e90SDaniel Mrzyglod 	clock_gettime(CLOCK_REALTIME, &sys_time);
482ab129e90SDaniel Mrzyglod 	rte_eth_timesync_read_time(ptp_data.current_ptp_port, &net_time);
483ab129e90SDaniel Mrzyglod 
484ab129e90SDaniel Mrzyglod 	nsec = (int64_t)timespec64_to_ns(&net_time) -
485ab129e90SDaniel Mrzyglod 	       (int64_t)timespec64_to_ns(&sys_time);
486ab129e90SDaniel Mrzyglod 
487ab129e90SDaniel Mrzyglod 	ptp_data.new_adj = ns_to_timeval(nsec);
488ab129e90SDaniel Mrzyglod 
489ab129e90SDaniel Mrzyglod 	/*
490ab129e90SDaniel Mrzyglod 	 * If difference between kernel time and system time in NIC is too big
491ab129e90SDaniel Mrzyglod 	 * (more than +/- 20 microseconds), use clock_settime to set directly
492ab129e90SDaniel Mrzyglod 	 * the kernel time, as adjtime is better for small adjustments (takes
493ab129e90SDaniel Mrzyglod 	 * longer to adjust the time).
494ab129e90SDaniel Mrzyglod 	 */
495ab129e90SDaniel Mrzyglod 
496ab129e90SDaniel Mrzyglod 	if (nsec > KERNEL_TIME_ADJUST_LIMIT || nsec < -KERNEL_TIME_ADJUST_LIMIT)
497ab129e90SDaniel Mrzyglod 		clock_settime(CLOCK_REALTIME, &net_time);
498ab129e90SDaniel Mrzyglod 	else
499ab129e90SDaniel Mrzyglod 		adjtime(&ptp_data.new_adj, 0);
500ab129e90SDaniel Mrzyglod 
501ab129e90SDaniel Mrzyglod 
502ab129e90SDaniel Mrzyglod }
503ab129e90SDaniel Mrzyglod 
504ab129e90SDaniel Mrzyglod /*
505ab129e90SDaniel Mrzyglod  * Parse the DELAY_RESP message.
506ab129e90SDaniel Mrzyglod  */
507ab129e90SDaniel Mrzyglod static void
508ab129e90SDaniel Mrzyglod parse_drsp(struct ptpv2_data_slave_ordinary *ptp_data)
509ab129e90SDaniel Mrzyglod {
510ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m = ptp_data->m;
511ab129e90SDaniel Mrzyglod 	struct ptp_message *ptp_msg;
512ab129e90SDaniel Mrzyglod 	struct tstamp *rx_tstamp;
513ab129e90SDaniel Mrzyglod 	uint16_t seq_id;
514ab129e90SDaniel Mrzyglod 
515ab129e90SDaniel Mrzyglod 	ptp_msg = (struct ptp_message *) (rte_pktmbuf_mtod(m, char *) +
5166d13ea8eSOlivier Matz 					sizeof(struct rte_ether_hdr));
517ab129e90SDaniel Mrzyglod 	seq_id = rte_be_to_cpu_16(ptp_msg->delay_resp.hdr.seq_id);
518ab129e90SDaniel Mrzyglod 	if (memcmp(&ptp_data->client_clock_id,
519ab129e90SDaniel Mrzyglod 		   &ptp_msg->delay_resp.req_port_id.clock_id,
520ab129e90SDaniel Mrzyglod 		   sizeof(struct clock_id)) == 0) {
521ab129e90SDaniel Mrzyglod 		if (seq_id == ptp_data->seqID_FOLLOWUP) {
522ab129e90SDaniel Mrzyglod 			rx_tstamp = &ptp_msg->delay_resp.rx_tstamp;
523ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_nsec = ntohl(rx_tstamp->ns);
524ab129e90SDaniel Mrzyglod 			ptp_data->tstamp4.tv_sec =
525ab129e90SDaniel Mrzyglod 				((uint64_t)ntohl(rx_tstamp->sec_lsb)) |
526ab129e90SDaniel Mrzyglod 				(((uint64_t)ntohs(rx_tstamp->sec_msb)) << 32);
527ab129e90SDaniel Mrzyglod 
528ab129e90SDaniel Mrzyglod 			/* Evaluate the delta for adjustment. */
529ab129e90SDaniel Mrzyglod 			ptp_data->delta = delta_eval(ptp_data);
530ab129e90SDaniel Mrzyglod 
531ab129e90SDaniel Mrzyglod 			rte_eth_timesync_adjust_time(ptp_data->portid,
532ab129e90SDaniel Mrzyglod 						     ptp_data->delta);
533ab129e90SDaniel Mrzyglod 
534ab129e90SDaniel Mrzyglod 			ptp_data->current_ptp_port = ptp_data->portid;
535ab129e90SDaniel Mrzyglod 
536ab129e90SDaniel Mrzyglod 			/* Update kernel time if enabled in app parameters. */
537ab129e90SDaniel Mrzyglod 			if (ptp_data->kernel_time_set == 1)
538ab129e90SDaniel Mrzyglod 				update_kernel_time();
539ab129e90SDaniel Mrzyglod 
540ab129e90SDaniel Mrzyglod 
541ab129e90SDaniel Mrzyglod 
542ab129e90SDaniel Mrzyglod 		}
543ab129e90SDaniel Mrzyglod 	}
544ab129e90SDaniel Mrzyglod }
545ab129e90SDaniel Mrzyglod 
546ab129e90SDaniel Mrzyglod /* This function processes PTP packets, implementing slave PTP IEEE1588 L2
547ab129e90SDaniel Mrzyglod  * functionality.
548ab129e90SDaniel Mrzyglod  */
549ab129e90SDaniel Mrzyglod static void
55047523597SZhiyong Yang parse_ptp_frames(uint16_t portid, struct rte_mbuf *m) {
551ab129e90SDaniel Mrzyglod 	struct ptp_header *ptp_hdr;
5526d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth_hdr;
553ab129e90SDaniel Mrzyglod 	uint16_t eth_type;
554ab129e90SDaniel Mrzyglod 
5556d13ea8eSOlivier Matz 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
556ab129e90SDaniel Mrzyglod 	eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
557ab129e90SDaniel Mrzyglod 
558ab129e90SDaniel Mrzyglod 	if (eth_type == PTP_PROTOCOL) {
559ab129e90SDaniel Mrzyglod 		ptp_data.m = m;
560ab129e90SDaniel Mrzyglod 		ptp_data.portid = portid;
561ab129e90SDaniel Mrzyglod 		ptp_hdr = (struct ptp_header *)(rte_pktmbuf_mtod(m, char *)
5626d13ea8eSOlivier Matz 					+ sizeof(struct rte_ether_hdr));
563ab129e90SDaniel Mrzyglod 
564ab129e90SDaniel Mrzyglod 		switch (ptp_hdr->msg_type) {
565ab129e90SDaniel Mrzyglod 		case SYNC:
566ab129e90SDaniel Mrzyglod 			parse_sync(&ptp_data, m->timesync);
567ab129e90SDaniel Mrzyglod 			break;
568ab129e90SDaniel Mrzyglod 		case FOLLOW_UP:
569ab129e90SDaniel Mrzyglod 			parse_fup(&ptp_data);
570ab129e90SDaniel Mrzyglod 			break;
571ab129e90SDaniel Mrzyglod 		case DELAY_RESP:
572ab129e90SDaniel Mrzyglod 			parse_drsp(&ptp_data);
573ab129e90SDaniel Mrzyglod 			print_clock_info(&ptp_data);
574ab129e90SDaniel Mrzyglod 			break;
575ab129e90SDaniel Mrzyglod 		default:
576ab129e90SDaniel Mrzyglod 			break;
577ab129e90SDaniel Mrzyglod 		}
578ab129e90SDaniel Mrzyglod 	}
579ab129e90SDaniel Mrzyglod }
580ab129e90SDaniel Mrzyglod 
581ab129e90SDaniel Mrzyglod /*
582ab129e90SDaniel Mrzyglod  * The lcore main. This is the main thread that does the work, reading from an
583ab129e90SDaniel Mrzyglod  * input port and writing to an output port.
584ab129e90SDaniel Mrzyglod  */
585ab129e90SDaniel Mrzyglod static __attribute__((noreturn)) void
586ab129e90SDaniel Mrzyglod lcore_main(void)
587ab129e90SDaniel Mrzyglod {
58847523597SZhiyong Yang 	uint16_t portid;
589ab129e90SDaniel Mrzyglod 	unsigned nb_rx;
590ab129e90SDaniel Mrzyglod 	struct rte_mbuf *m;
591ab129e90SDaniel Mrzyglod 
592ab129e90SDaniel Mrzyglod 	/*
593ab129e90SDaniel Mrzyglod 	 * Check that the port is on the same NUMA node as the polling thread
594ab129e90SDaniel Mrzyglod 	 * for best performance.
595ab129e90SDaniel Mrzyglod 	 */
596ab129e90SDaniel Mrzyglod 	printf("\nCore %u Waiting for SYNC packets. [Ctrl+C to quit]\n",
597ab129e90SDaniel Mrzyglod 			rte_lcore_id());
598ab129e90SDaniel Mrzyglod 
599ab129e90SDaniel Mrzyglod 	/* Run until the application is quit or killed. */
600ab129e90SDaniel Mrzyglod 
601ab129e90SDaniel Mrzyglod 	while (1) {
602ab129e90SDaniel Mrzyglod 		/* Read packet from RX queues. */
603ab129e90SDaniel Mrzyglod 		for (portid = 0; portid < ptp_enabled_port_nb; portid++) {
604ab129e90SDaniel Mrzyglod 
605ab129e90SDaniel Mrzyglod 			portid = ptp_enabled_ports[portid];
606ab129e90SDaniel Mrzyglod 			nb_rx = rte_eth_rx_burst(portid, 0, &m, 1);
607ab129e90SDaniel Mrzyglod 
608ab129e90SDaniel Mrzyglod 			if (likely(nb_rx == 0))
609ab129e90SDaniel Mrzyglod 				continue;
610ab129e90SDaniel Mrzyglod 
611ab129e90SDaniel Mrzyglod 			if (m->ol_flags & PKT_RX_IEEE1588_PTP)
612ab129e90SDaniel Mrzyglod 				parse_ptp_frames(portid, m);
613ab129e90SDaniel Mrzyglod 
614ab129e90SDaniel Mrzyglod 			rte_pktmbuf_free(m);
615ab129e90SDaniel Mrzyglod 		}
616ab129e90SDaniel Mrzyglod 	}
617ab129e90SDaniel Mrzyglod }
618ab129e90SDaniel Mrzyglod 
619ab129e90SDaniel Mrzyglod static void
620ab129e90SDaniel Mrzyglod print_usage(const char *prgname)
621ab129e90SDaniel Mrzyglod {
622ab129e90SDaniel Mrzyglod 	printf("%s [EAL options] -- -p PORTMASK -T VALUE\n"
623ab129e90SDaniel Mrzyglod 		" -T VALUE: 0 - Disable, 1 - Enable Linux Clock"
624ab129e90SDaniel Mrzyglod 		" Synchronization (0 default)\n"
625ab129e90SDaniel Mrzyglod 		" -p PORTMASK: hexadecimal bitmask of ports to configure\n",
626ab129e90SDaniel Mrzyglod 		prgname);
627ab129e90SDaniel Mrzyglod }
628ab129e90SDaniel Mrzyglod 
629ab129e90SDaniel Mrzyglod static int
630ab129e90SDaniel Mrzyglod ptp_parse_portmask(const char *portmask)
631ab129e90SDaniel Mrzyglod {
632ab129e90SDaniel Mrzyglod 	char *end = NULL;
633ab129e90SDaniel Mrzyglod 	unsigned long pm;
634ab129e90SDaniel Mrzyglod 
635ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
636ab129e90SDaniel Mrzyglod 	pm = strtoul(portmask, &end, 16);
637ab129e90SDaniel Mrzyglod 
638ab129e90SDaniel Mrzyglod 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
639ab129e90SDaniel Mrzyglod 		return -1;
640ab129e90SDaniel Mrzyglod 
641ab129e90SDaniel Mrzyglod 	if (pm == 0)
642ab129e90SDaniel Mrzyglod 		return -1;
643ab129e90SDaniel Mrzyglod 
644ab129e90SDaniel Mrzyglod 	return pm;
645ab129e90SDaniel Mrzyglod }
646ab129e90SDaniel Mrzyglod 
647ab129e90SDaniel Mrzyglod static int
648ab129e90SDaniel Mrzyglod parse_ptp_kernel(const char *param)
649ab129e90SDaniel Mrzyglod {
650ab129e90SDaniel Mrzyglod 	char *end = NULL;
651ab129e90SDaniel Mrzyglod 	unsigned long pm;
652ab129e90SDaniel Mrzyglod 
653ab129e90SDaniel Mrzyglod 	/* Parse the hexadecimal string. */
654ab129e90SDaniel Mrzyglod 	pm = strtoul(param, &end, 16);
655ab129e90SDaniel Mrzyglod 
656ab129e90SDaniel Mrzyglod 	if ((param[0] == '\0') || (end == NULL) || (*end != '\0'))
657ab129e90SDaniel Mrzyglod 		return -1;
658ab129e90SDaniel Mrzyglod 	if (pm == 0)
659ab129e90SDaniel Mrzyglod 		return 0;
660ab129e90SDaniel Mrzyglod 
661ab129e90SDaniel Mrzyglod 	return 1;
662ab129e90SDaniel Mrzyglod }
663ab129e90SDaniel Mrzyglod 
664ab129e90SDaniel Mrzyglod /* Parse the commandline arguments. */
665ab129e90SDaniel Mrzyglod static int
666ab129e90SDaniel Mrzyglod ptp_parse_args(int argc, char **argv)
667ab129e90SDaniel Mrzyglod {
668ab129e90SDaniel Mrzyglod 	int opt, ret;
669ab129e90SDaniel Mrzyglod 	char **argvopt;
670ab129e90SDaniel Mrzyglod 	int option_index;
671ab129e90SDaniel Mrzyglod 	char *prgname = argv[0];
672ab129e90SDaniel Mrzyglod 	static struct option lgopts[] = { {NULL, 0, 0, 0} };
673ab129e90SDaniel Mrzyglod 
674ab129e90SDaniel Mrzyglod 	argvopt = argv;
675ab129e90SDaniel Mrzyglod 
676ab129e90SDaniel Mrzyglod 	while ((opt = getopt_long(argc, argvopt, "p:T:",
677ab129e90SDaniel Mrzyglod 				  lgopts, &option_index)) != EOF) {
678ab129e90SDaniel Mrzyglod 
679ab129e90SDaniel Mrzyglod 		switch (opt) {
680ab129e90SDaniel Mrzyglod 
681ab129e90SDaniel Mrzyglod 		/* Portmask. */
682ab129e90SDaniel Mrzyglod 		case 'p':
683ab129e90SDaniel Mrzyglod 			ptp_enabled_port_mask = ptp_parse_portmask(optarg);
684ab129e90SDaniel Mrzyglod 			if (ptp_enabled_port_mask == 0) {
685ab129e90SDaniel Mrzyglod 				printf("invalid portmask\n");
686ab129e90SDaniel Mrzyglod 				print_usage(prgname);
687ab129e90SDaniel Mrzyglod 				return -1;
688ab129e90SDaniel Mrzyglod 			}
689ab129e90SDaniel Mrzyglod 			break;
690ab129e90SDaniel Mrzyglod 		/* Time synchronization. */
691ab129e90SDaniel Mrzyglod 		case 'T':
692ab129e90SDaniel Mrzyglod 			ret = parse_ptp_kernel(optarg);
693ab129e90SDaniel Mrzyglod 			if (ret < 0) {
694ab129e90SDaniel Mrzyglod 				print_usage(prgname);
695ab129e90SDaniel Mrzyglod 				return -1;
696ab129e90SDaniel Mrzyglod 			}
697ab129e90SDaniel Mrzyglod 
698ab129e90SDaniel Mrzyglod 			ptp_data.kernel_time_set = ret;
699ab129e90SDaniel Mrzyglod 			break;
700ab129e90SDaniel Mrzyglod 
701ab129e90SDaniel Mrzyglod 		default:
702ab129e90SDaniel Mrzyglod 			print_usage(prgname);
703ab129e90SDaniel Mrzyglod 			return -1;
704ab129e90SDaniel Mrzyglod 		}
705ab129e90SDaniel Mrzyglod 	}
706ab129e90SDaniel Mrzyglod 
707ab129e90SDaniel Mrzyglod 	argv[optind-1] = prgname;
708ab129e90SDaniel Mrzyglod 
7099d5ca532SKeith Wiles 	optind = 1; /* Reset getopt lib. */
710ab129e90SDaniel Mrzyglod 
711ab129e90SDaniel Mrzyglod 	return 0;
712ab129e90SDaniel Mrzyglod }
713ab129e90SDaniel Mrzyglod 
714ab129e90SDaniel Mrzyglod /*
715ab129e90SDaniel Mrzyglod  * The main function, which does initialization and calls the per-lcore
716ab129e90SDaniel Mrzyglod  * functions.
717ab129e90SDaniel Mrzyglod  */
718ab129e90SDaniel Mrzyglod int
719ab129e90SDaniel Mrzyglod main(int argc, char *argv[])
720ab129e90SDaniel Mrzyglod {
721ab129e90SDaniel Mrzyglod 	unsigned nb_ports;
722ab129e90SDaniel Mrzyglod 
72347523597SZhiyong Yang 	uint16_t portid;
724ab129e90SDaniel Mrzyglod 
725ab129e90SDaniel Mrzyglod 	/* Initialize the Environment Abstraction Layer (EAL). */
726ab129e90SDaniel Mrzyglod 	int ret = rte_eal_init(argc, argv);
727ab129e90SDaniel Mrzyglod 
728ab129e90SDaniel Mrzyglod 	if (ret < 0)
729ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
730ab129e90SDaniel Mrzyglod 
731ab129e90SDaniel Mrzyglod 	memset(&ptp_data, '\0', sizeof(struct ptpv2_data_slave_ordinary));
732ab129e90SDaniel Mrzyglod 
733ab129e90SDaniel Mrzyglod 	argc -= ret;
734ab129e90SDaniel Mrzyglod 	argv += ret;
735ab129e90SDaniel Mrzyglod 
736ab129e90SDaniel Mrzyglod 	ret = ptp_parse_args(argc, argv);
737ab129e90SDaniel Mrzyglod 	if (ret < 0)
738ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
739ab129e90SDaniel Mrzyglod 
740ab129e90SDaniel Mrzyglod 	/* Check that there is an even number of ports to send/receive on. */
741d9a42a69SThomas Monjalon 	nb_ports = rte_eth_dev_count_avail();
742ab129e90SDaniel Mrzyglod 
743ab129e90SDaniel Mrzyglod 	/* Creates a new mempool in memory to hold the mbufs. */
744ab129e90SDaniel Mrzyglod 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
745ab129e90SDaniel Mrzyglod 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
746ab129e90SDaniel Mrzyglod 
747ab129e90SDaniel Mrzyglod 	if (mbuf_pool == NULL)
748ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
749ab129e90SDaniel Mrzyglod 
750ab129e90SDaniel Mrzyglod 	/* Initialize all ports. */
7518728ccf3SThomas Monjalon 	RTE_ETH_FOREACH_DEV(portid) {
752ab129e90SDaniel Mrzyglod 		if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
753ab129e90SDaniel Mrzyglod 			if (port_init(portid, mbuf_pool) == 0) {
754ab129e90SDaniel Mrzyglod 				ptp_enabled_ports[ptp_enabled_port_nb] = portid;
755ab129e90SDaniel Mrzyglod 				ptp_enabled_port_nb++;
756ab129e90SDaniel Mrzyglod 			} else {
757ab129e90SDaniel Mrzyglod 				rte_exit(EXIT_FAILURE,
758ab129e90SDaniel Mrzyglod 					 "Cannot init port %"PRIu8 "\n",
759ab129e90SDaniel Mrzyglod 					 portid);
760ab129e90SDaniel Mrzyglod 			}
761ab129e90SDaniel Mrzyglod 		} else
762ab129e90SDaniel Mrzyglod 			printf("Skipping disabled port %u\n", portid);
763ab129e90SDaniel Mrzyglod 	}
764ab129e90SDaniel Mrzyglod 
765ab129e90SDaniel Mrzyglod 	if (ptp_enabled_port_nb == 0) {
766ab129e90SDaniel Mrzyglod 		rte_exit(EXIT_FAILURE,
767ab129e90SDaniel Mrzyglod 			"All available ports are disabled."
768ab129e90SDaniel Mrzyglod 			" Please set portmask.\n");
769ab129e90SDaniel Mrzyglod 	}
770ab129e90SDaniel Mrzyglod 
771ab129e90SDaniel Mrzyglod 	if (rte_lcore_count() > 1)
772ab129e90SDaniel Mrzyglod 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
773ab129e90SDaniel Mrzyglod 
774ab129e90SDaniel Mrzyglod 	/* Call lcore_main on the master core only. */
775ab129e90SDaniel Mrzyglod 	lcore_main();
776ab129e90SDaniel Mrzyglod 
777ab129e90SDaniel Mrzyglod 	return 0;
778ab129e90SDaniel Mrzyglod }
779