xref: /dpdk/examples/ptpclient/ptpclient.c (revision 37dda90ee15b7098bc48356868a87d34f727eecc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015 Intel Corporation
3  */
4 
5 /*
6  * This application is a simple Layer 2 PTP v2 client. It shows delta values
7  * which are used to synchronize the PHC clock. if the "-T 1" parameter is
8  * passed to the application the Linux kernel clock is also synchronized.
9  */
10 
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <inttypes.h>
14 #include <rte_eal.h>
15 #include <rte_ethdev.h>
16 #include <rte_cycles.h>
17 #include <rte_lcore.h>
18 #include <rte_mbuf.h>
19 #include <rte_ip.h>
20 #include <limits.h>
21 #include <sys/time.h>
22 #include <getopt.h>
23 #include <signal.h>
24 
25 static volatile bool force_quit;
26 
27 #define RX_RING_SIZE 1024
28 #define TX_RING_SIZE 1024
29 
30 #define NUM_MBUFS            8191
31 #define MBUF_CACHE_SIZE       250
32 
33 /* Values for the PTP messageType field. */
34 #define SYNC                  0x0
35 #define DELAY_REQ             0x1
36 #define PDELAY_REQ            0x2
37 #define PDELAY_RESP           0x3
38 #define FOLLOW_UP             0x8
39 #define DELAY_RESP            0x9
40 #define PDELAY_RESP_FOLLOW_UP 0xA
41 #define ANNOUNCE              0xB
42 #define SIGNALING             0xC
43 #define MANAGEMENT            0xD
44 
45 #define NSEC_PER_SEC        1000000000L
46 #define KERNEL_TIME_ADJUST_LIMIT  20000
47 #define PTP_PROTOCOL             0x88F7
48 
49 #define KP 0.7
50 #define KI 0.3
51 #define FREQ_EST_MARGIN 0.001
52 
53 enum servo_state {
54 	SERVO_UNLOCKED,
55 	SERVO_JUMP,
56 	SERVO_LOCKED,
57 };
58 
59 struct pi_servo {
60 	double offset[2];
61 	double local[2];
62 	double drift;
63 	double last_freq;
64 	int count;
65 
66 	double max_frequency;
67 	double step_threshold;
68 	double first_step_threshold;
69 	int first_update;
70 };
71 
72 enum controller_mode {
73 	MODE_NONE,
74 	MODE_PI,
75 	MAX_ALL
76 } mode = MODE_NONE;
77 
78 struct rte_mempool *mbuf_pool;
79 uint32_t ptp_enabled_port_mask;
80 uint8_t ptp_enabled_port_nb;
81 static uint8_t ptp_enabled_ports[RTE_MAX_ETHPORTS];
82 
83 static const struct rte_ether_addr ether_multicast = {
84 	.addr_bytes = {0x01, 0x1b, 0x19, 0x0, 0x0, 0x0}
85 };
86 
87 /* Structs used for PTP handling. */
88 struct tstamp {
89 	uint16_t   sec_msb;
90 	uint32_t   sec_lsb;
91 	uint32_t   ns;
92 }  __rte_packed;
93 
94 struct clock_id {
95 	uint8_t id[8];
96 };
97 
98 struct port_id {
99 	struct clock_id        clock_id;
100 	uint16_t               port_number;
101 }  __rte_packed;
102 
103 struct ptp_header {
104 	uint8_t              msg_type;
105 	uint8_t              ver;
106 	uint16_t             message_length;
107 	uint8_t              domain_number;
108 	uint8_t              reserved1;
109 	uint8_t              flag_field[2];
110 	int64_t              correction;
111 	uint32_t             reserved2;
112 	struct port_id       source_port_id;
113 	uint16_t             seq_id;
114 	uint8_t              control;
115 	int8_t               log_message_interval;
116 } __rte_packed;
117 
118 struct sync_msg {
119 	struct ptp_header   hdr;
120 	struct tstamp       origin_tstamp;
121 } __rte_packed;
122 
123 struct follow_up_msg {
124 	struct ptp_header   hdr;
125 	struct tstamp       precise_origin_tstamp;
126 	uint8_t             suffix[];
127 } __rte_packed;
128 
129 struct delay_req_msg {
130 	struct ptp_header   hdr;
131 	struct tstamp       origin_tstamp;
132 } __rte_packed;
133 
134 struct delay_resp_msg {
135 	struct ptp_header    hdr;
136 	struct tstamp        rx_tstamp;
137 	struct port_id       req_port_id;
138 	uint8_t              suffix[];
139 } __rte_packed;
140 
141 struct ptp_message {
142 	union {
143 		struct ptp_header          header;
144 		struct sync_msg            sync;
145 		struct delay_req_msg       delay_req;
146 		struct follow_up_msg       follow_up;
147 		struct delay_resp_msg      delay_resp;
148 	} __rte_packed;
149 };
150 
151 struct ptpv2_time_receiver_ordinary {
152 	struct rte_mbuf *m;
153 	struct timespec tstamp1;
154 	struct timespec tstamp2;
155 	struct timespec tstamp3;
156 	struct timespec tstamp4;
157 	struct clock_id client_clock_id;
158 	struct clock_id transmitter_clock_id;
159 	struct timeval new_adj;
160 	int64_t delta;
161 	uint16_t portid;
162 	uint16_t seqID_SYNC;
163 	uint16_t seqID_FOLLOWUP;
164 	uint8_t ptpset;
165 	uint8_t kernel_time_set;
166 	uint16_t current_ptp_port;
167 	int64_t master_offset;
168 	int64_t path_delay;
169 	struct pi_servo *servo;
170 };
171 
172 static struct ptpv2_time_receiver_ordinary ptp_data;
173 
174 static inline uint64_t timespec64_to_ns(const struct timespec *ts)
175 {
176 	return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
177 }
178 
179 static struct timeval
180 ns_to_timeval(int64_t nsec)
181 {
182 	struct timespec t_spec = {0, 0};
183 	struct timeval t_eval = {0, 0};
184 	int32_t rem;
185 
186 	if (nsec == 0)
187 		return t_eval;
188 	rem = nsec % NSEC_PER_SEC;
189 	t_spec.tv_sec = nsec / NSEC_PER_SEC;
190 
191 	if (rem < 0) {
192 		t_spec.tv_sec--;
193 		rem += NSEC_PER_SEC;
194 	}
195 
196 	t_spec.tv_nsec = rem;
197 	t_eval.tv_sec = t_spec.tv_sec;
198 	t_eval.tv_usec = t_spec.tv_nsec / 1000;
199 
200 	return t_eval;
201 }
202 
203 /*
204  * Initializes a given port using global settings and with the RX buffers
205  * coming from the mbuf_pool passed as a parameter.
206  */
207 static inline int
208 port_init(uint16_t port, struct rte_mempool *mbuf_pool)
209 {
210 	struct rte_eth_dev_info dev_info;
211 	struct rte_eth_conf port_conf;
212 	const uint16_t rx_rings = 1;
213 	const uint16_t tx_rings = 1;
214 	int retval;
215 	uint16_t q;
216 	uint16_t nb_rxd = RX_RING_SIZE;
217 	uint16_t nb_txd = TX_RING_SIZE;
218 
219 	if (!rte_eth_dev_is_valid_port(port))
220 		return -1;
221 
222 	memset(&port_conf, 0, sizeof(struct rte_eth_conf));
223 
224 	retval = rte_eth_dev_info_get(port, &dev_info);
225 	if (retval != 0) {
226 		printf("Error during getting device (port %u) info: %s\n",
227 				port, strerror(-retval));
228 
229 		return retval;
230 	}
231 
232 	if (dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP)
233 		port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
234 
235 	if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
236 		port_conf.txmode.offloads |=
237 			RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
238 	/* Force full Tx path in the driver, required for IEEE1588 */
239 	port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
240 
241 	/* Configure the Ethernet device. */
242 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
243 	if (retval != 0)
244 		return retval;
245 
246 	retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
247 	if (retval != 0)
248 		return retval;
249 
250 	/* Allocate and set up 1 RX queue per Ethernet port. */
251 	for (q = 0; q < rx_rings; q++) {
252 		struct rte_eth_rxconf *rxconf;
253 
254 		rxconf = &dev_info.default_rxconf;
255 		rxconf->offloads = port_conf.rxmode.offloads;
256 
257 		retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
258 				rte_eth_dev_socket_id(port), rxconf, mbuf_pool);
259 
260 		if (retval < 0)
261 			return retval;
262 	}
263 
264 	/* Allocate and set up 1 TX queue per Ethernet port. */
265 	for (q = 0; q < tx_rings; q++) {
266 		struct rte_eth_txconf *txconf;
267 
268 		txconf = &dev_info.default_txconf;
269 		txconf->offloads = port_conf.txmode.offloads;
270 
271 		retval = rte_eth_tx_queue_setup(port, q, nb_txd,
272 				rte_eth_dev_socket_id(port), txconf);
273 		if (retval < 0)
274 			return retval;
275 	}
276 
277 	/* Start the Ethernet port. */
278 	retval = rte_eth_dev_start(port);
279 	if (retval < 0)
280 		return retval;
281 
282 	/* Enable timesync timestamping for the Ethernet device */
283 	retval = rte_eth_timesync_enable(port);
284 	if (retval < 0) {
285 		printf("Timesync enable failed: %d\n", retval);
286 		return retval;
287 	}
288 
289 	/* Enable RX in promiscuous mode for the Ethernet device. */
290 	retval = rte_eth_promiscuous_enable(port);
291 	if (retval != 0) {
292 		printf("Promiscuous mode enable failed: %s\n",
293 			rte_strerror(-retval));
294 		return retval;
295 	}
296 
297 	/*
298 	 * If the clock servo controller is enabled, the PMD must support
299 	 * adjustment of the clock frequency.
300 	 */
301 	if (mode != MODE_NONE) {
302 		retval = rte_eth_timesync_adjust_freq(port, 0);
303 		if (retval == -ENOTSUP) {
304 			printf("The servo controller cannot work on devices that"
305 					" do not support frequency adjustment.\n");
306 			return retval;
307 		}
308 	}
309 
310 	return 0;
311 }
312 
313 static void
314 print_clock_info(struct ptpv2_time_receiver_ordinary *ptp_data)
315 {
316 	int64_t nsec;
317 	struct timespec net_time, sys_time;
318 
319 	printf("time transmitter clock id: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
320 		ptp_data->transmitter_clock_id.id[0],
321 		ptp_data->transmitter_clock_id.id[1],
322 		ptp_data->transmitter_clock_id.id[2],
323 		ptp_data->transmitter_clock_id.id[3],
324 		ptp_data->transmitter_clock_id.id[4],
325 		ptp_data->transmitter_clock_id.id[5],
326 		ptp_data->transmitter_clock_id.id[6],
327 		ptp_data->transmitter_clock_id.id[7]);
328 
329 	printf("\nT2 - time receiver clock.  %lds %ldns",
330 			(ptp_data->tstamp2.tv_sec),
331 			(ptp_data->tstamp2.tv_nsec));
332 
333 	printf("\nT1 - time transmitter clock.  %lds %ldns ",
334 			ptp_data->tstamp1.tv_sec,
335 			(ptp_data->tstamp1.tv_nsec));
336 
337 	printf("\nT3 - time receiver clock.  %lds %ldns",
338 			ptp_data->tstamp3.tv_sec,
339 			(ptp_data->tstamp3.tv_nsec));
340 
341 	printf("\nT4 - time transmitter clock.  %lds %ldns\n",
342 			ptp_data->tstamp4.tv_sec,
343 			(ptp_data->tstamp4.tv_nsec));
344 
345 	if (mode == MODE_NONE) {
346 		printf("\nDelta between transmitter and receiver clocks:%"PRId64"ns\n",
347 			ptp_data->delta);
348 
349 		clock_gettime(CLOCK_REALTIME, &sys_time);
350 		rte_eth_timesync_read_time(ptp_data->current_ptp_port,
351 					   &net_time);
352 
353 		time_t ts = net_time.tv_sec;
354 
355 		printf("\n\nComparison between Linux kernel Time and PTP:");
356 
357 		printf("\nCurrent PTP Time: %.24s %.9ld ns",
358 			ctime(&ts), net_time.tv_nsec);
359 
360 		nsec = (int64_t)timespec64_to_ns(&net_time) -
361 			(int64_t)timespec64_to_ns(&sys_time);
362 		ptp_data->new_adj = ns_to_timeval(nsec);
363 
364 		gettimeofday(&ptp_data->new_adj, NULL);
365 
366 		time_t tp = ptp_data->new_adj.tv_sec;
367 
368 		printf("\nCurrent SYS Time: %.24s %.6ld ns",
369 			ctime(&tp), ptp_data->new_adj.tv_usec);
370 
371 		printf("\nDelta between PTP and Linux Kernel time:%"PRId64"ns\n",
372 			nsec);
373 	}
374 
375 	if (mode == MODE_PI) {
376 		printf("path delay: %"PRId64"ns\n", ptp_data->path_delay);
377 		printf("time transmitter offset: %"PRId64"ns\n", ptp_data->master_offset);
378 	}
379 
380 	printf("[Ctrl+C to quit]\n");
381 
382 	/* Clear screen and put cursor in column 1, row 1 */
383 	printf("\033[2J\033[1;1H");
384 }
385 
386 static int64_t
387 delta_eval(struct ptpv2_time_receiver_ordinary *ptp_data)
388 {
389 	int64_t delta;
390 	uint64_t t1 = 0;
391 	uint64_t t2 = 0;
392 	uint64_t t3 = 0;
393 	uint64_t t4 = 0;
394 
395 	t1 = timespec64_to_ns(&ptp_data->tstamp1);
396 	t2 = timespec64_to_ns(&ptp_data->tstamp2);
397 	t3 = timespec64_to_ns(&ptp_data->tstamp3);
398 	t4 = timespec64_to_ns(&ptp_data->tstamp4);
399 
400 	delta = -((int64_t)((t2 - t1) - (t4 - t3))) / 2;
401 
402 	return delta;
403 }
404 
405 /*
406  * Parse the PTP SYNC message.
407  */
408 static void
409 parse_sync(struct ptpv2_time_receiver_ordinary *ptp_data, uint16_t rx_tstamp_idx)
410 {
411 	struct ptp_header *ptp_hdr;
412 
413 	ptp_hdr = rte_pktmbuf_mtod_offset(ptp_data->m, struct ptp_header *,
414 					  sizeof(struct rte_ether_hdr));
415 	ptp_data->seqID_SYNC = rte_be_to_cpu_16(ptp_hdr->seq_id);
416 
417 	if (ptp_data->ptpset == 0) {
418 		rte_memcpy(&ptp_data->transmitter_clock_id,
419 				&ptp_hdr->source_port_id.clock_id,
420 				sizeof(struct clock_id));
421 		ptp_data->ptpset = 1;
422 	}
423 
424 	if (memcmp(&ptp_hdr->source_port_id.clock_id,
425 			&ptp_hdr->source_port_id.clock_id,
426 			sizeof(struct clock_id)) == 0) {
427 
428 		if (ptp_data->ptpset == 1)
429 			rte_eth_timesync_read_rx_timestamp(ptp_data->portid,
430 					&ptp_data->tstamp2, rx_tstamp_idx);
431 	}
432 
433 }
434 
435 /*
436  * Parse the PTP FOLLOWUP message and send DELAY_REQ to the main clock.
437  */
438 static void
439 parse_fup(struct ptpv2_time_receiver_ordinary *ptp_data)
440 {
441 	struct rte_ether_hdr *eth_hdr;
442 	struct rte_ether_addr eth_addr;
443 	struct ptp_header *ptp_hdr;
444 	struct clock_id *client_clkid;
445 	struct ptp_message *ptp_msg;
446 	struct delay_req_msg *req_msg;
447 	struct rte_mbuf *created_pkt;
448 	struct tstamp *origin_tstamp;
449 	struct rte_ether_addr eth_multicast = ether_multicast;
450 	size_t pkt_size;
451 	int wait_us;
452 	struct rte_mbuf *m = ptp_data->m;
453 	int ret;
454 
455 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
456 	ptp_hdr = rte_pktmbuf_mtod_offset(m, struct ptp_header *,
457 					  sizeof(struct rte_ether_hdr));
458 	if (memcmp(&ptp_data->transmitter_clock_id,
459 			&ptp_hdr->source_port_id.clock_id,
460 			sizeof(struct clock_id)) != 0)
461 		return;
462 
463 	ptp_data->seqID_FOLLOWUP = rte_be_to_cpu_16(ptp_hdr->seq_id);
464 	ptp_msg = rte_pktmbuf_mtod_offset(m, struct ptp_message *,
465 					  sizeof(struct rte_ether_hdr));
466 
467 	origin_tstamp = &ptp_msg->follow_up.precise_origin_tstamp;
468 	ptp_data->tstamp1.tv_nsec = ntohl(origin_tstamp->ns);
469 	ptp_data->tstamp1.tv_sec =
470 		((uint64_t)ntohl(origin_tstamp->sec_lsb)) |
471 		(((uint64_t)ntohs(origin_tstamp->sec_msb)) << 32);
472 
473 	if (ptp_data->seqID_FOLLOWUP == ptp_data->seqID_SYNC) {
474 		ret = rte_eth_macaddr_get(ptp_data->portid, &eth_addr);
475 		if (ret != 0) {
476 			printf("\nCore %u: port %u failed to get MAC address: %s\n",
477 				rte_lcore_id(), ptp_data->portid,
478 				rte_strerror(-ret));
479 			return;
480 		}
481 
482 		created_pkt = rte_pktmbuf_alloc(mbuf_pool);
483 		pkt_size = sizeof(struct rte_ether_hdr) +
484 			sizeof(struct delay_req_msg);
485 
486 		if (rte_pktmbuf_append(created_pkt, pkt_size) == NULL) {
487 			rte_pktmbuf_free(created_pkt);
488 			return;
489 		}
490 		created_pkt->data_len = pkt_size;
491 		created_pkt->pkt_len = pkt_size;
492 		eth_hdr = rte_pktmbuf_mtod(created_pkt, struct rte_ether_hdr *);
493 		rte_ether_addr_copy(&eth_addr, &eth_hdr->src_addr);
494 
495 		/* Set multicast address 01-1B-19-00-00-00. */
496 		rte_ether_addr_copy(&eth_multicast, &eth_hdr->dst_addr);
497 
498 		eth_hdr->ether_type = htons(PTP_PROTOCOL);
499 		req_msg = rte_pktmbuf_mtod_offset(created_pkt,
500 			struct delay_req_msg *, sizeof(struct
501 			rte_ether_hdr));
502 
503 		req_msg->hdr.seq_id = htons(ptp_data->seqID_SYNC);
504 		req_msg->hdr.msg_type = DELAY_REQ;
505 		req_msg->hdr.ver = 2;
506 		req_msg->hdr.control = 1;
507 		req_msg->hdr.log_message_interval = 127;
508 		req_msg->hdr.message_length =
509 			htons(sizeof(struct delay_req_msg));
510 		req_msg->hdr.domain_number = ptp_hdr->domain_number;
511 
512 		/* Set up clock id. */
513 		client_clkid =
514 			&req_msg->hdr.source_port_id.clock_id;
515 
516 		client_clkid->id[0] = eth_hdr->src_addr.addr_bytes[0];
517 		client_clkid->id[1] = eth_hdr->src_addr.addr_bytes[1];
518 		client_clkid->id[2] = eth_hdr->src_addr.addr_bytes[2];
519 		client_clkid->id[3] = 0xFF;
520 		client_clkid->id[4] = 0xFE;
521 		client_clkid->id[5] = eth_hdr->src_addr.addr_bytes[3];
522 		client_clkid->id[6] = eth_hdr->src_addr.addr_bytes[4];
523 		client_clkid->id[7] = eth_hdr->src_addr.addr_bytes[5];
524 
525 		rte_memcpy(&ptp_data->client_clock_id,
526 			   client_clkid,
527 			   sizeof(struct clock_id));
528 
529 		/* Enable flag for hardware timestamping. */
530 		created_pkt->ol_flags |= RTE_MBUF_F_TX_IEEE1588_TMST;
531 
532 		/*Read value from NIC to prevent latching with old value. */
533 		rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
534 				&ptp_data->tstamp3);
535 
536 		/* Transmit the packet. */
537 		rte_eth_tx_burst(ptp_data->portid, 0, &created_pkt, 1);
538 
539 		wait_us = 0;
540 		ptp_data->tstamp3.tv_nsec = 0;
541 		ptp_data->tstamp3.tv_sec = 0;
542 
543 		/* Wait at least 1 us to read TX timestamp. */
544 		while ((rte_eth_timesync_read_tx_timestamp(ptp_data->portid,
545 				&ptp_data->tstamp3) < 0) && (wait_us < 1000)) {
546 			rte_delay_us(1);
547 			wait_us++;
548 		}
549 	}
550 }
551 
552 /*
553  * Update the kernel time with the difference between it and the current NIC
554  * time.
555  */
556 static inline void
557 update_kernel_time(void)
558 {
559 	int64_t nsec;
560 	struct timespec net_time, sys_time;
561 
562 	clock_gettime(CLOCK_REALTIME, &sys_time);
563 	rte_eth_timesync_read_time(ptp_data.current_ptp_port, &net_time);
564 
565 	nsec = (int64_t)timespec64_to_ns(&net_time) -
566 	       (int64_t)timespec64_to_ns(&sys_time);
567 
568 	ptp_data.new_adj = ns_to_timeval(nsec);
569 
570 	/*
571 	 * If difference between kernel time and system time in NIC is too big
572 	 * (more than +/- 20 microseconds), use clock_settime to set directly
573 	 * the kernel time, as adjtime is better for small adjustments (takes
574 	 * longer to adjust the time).
575 	 */
576 
577 	if (nsec > KERNEL_TIME_ADJUST_LIMIT || nsec < -KERNEL_TIME_ADJUST_LIMIT)
578 		clock_settime(CLOCK_REALTIME, &net_time);
579 	else
580 		adjtime(&ptp_data.new_adj, 0);
581 
582 
583 }
584 
585 static void
586 clock_path_delay(struct ptpv2_time_receiver_ordinary *ptp_data)
587 {
588 	uint64_t t1_ns, t2_ns, t3_ns, t4_ns;
589 	int64_t pd, diff;
590 
591 	t1_ns = timespec64_to_ns(&ptp_data->tstamp1);
592 	t2_ns = timespec64_to_ns(&ptp_data->tstamp2);
593 	t3_ns = timespec64_to_ns(&ptp_data->tstamp3);
594 	t4_ns = timespec64_to_ns(&ptp_data->tstamp4);
595 
596 	pd = (t2_ns - t3_ns) + (t4_ns - t1_ns);
597 	diff = t3_ns - t2_ns;
598 	if (diff <= INT32_MAX && diff >= INT32_MIN)
599 		ptp_data->path_delay = pd / 2;
600 	else
601 		ptp_data->path_delay = 0;
602 }
603 
604 static double
605 pi_sample(struct pi_servo *s, int64_t offset, double local_ts,
606 	  enum servo_state *state)
607 {
608 	double ki_term, ppb = s->last_freq;
609 	double freq_est_interval, localdiff;
610 
611 	switch (s->count) {
612 	case 0:
613 		s->offset[0] = offset;
614 		s->local[0] = local_ts;
615 		*state = SERVO_UNLOCKED;
616 		s->count = 1;
617 		break;
618 	case 1:
619 		s->offset[1] = offset;
620 		s->local[1] = local_ts;
621 
622 		/* Make sure the first sample is older than the second. */
623 		if (s->local[0] >= s->local[1]) {
624 			*state = SERVO_UNLOCKED;
625 			s->count = 0;
626 			break;
627 		}
628 
629 		/* Wait long enough before estimating the frequency offset. */
630 		localdiff = (s->local[1] - s->local[0]) / 1e9;
631 		localdiff += localdiff * FREQ_EST_MARGIN;
632 		freq_est_interval = 0.016 / KI;
633 		if (freq_est_interval > 1000.0)
634 			freq_est_interval = 1000.0;
635 
636 		if (localdiff < freq_est_interval) {
637 			*state = SERVO_UNLOCKED;
638 			break;
639 		}
640 
641 		/* Adjust drift by the measured frequency offset. */
642 		s->drift += (1e9 - s->drift) * (s->offset[1] - s->offset[0]) /
643 						(s->local[1] - s->local[0]);
644 
645 		if (s->drift < -s->max_frequency)
646 			s->drift = -s->max_frequency;
647 		else if (s->drift > s->max_frequency)
648 			s->drift = s->max_frequency;
649 
650 		if ((s->first_update &&
651 		     s->first_step_threshold &&
652 		     s->first_step_threshold < llabs(offset)) ||
653 		    (s->step_threshold &&
654 		     s->step_threshold < llabs(offset)))
655 			*state = SERVO_JUMP;
656 		else
657 			*state = SERVO_LOCKED;
658 
659 		ppb = s->drift;
660 		s->count = 2;
661 		break;
662 	case 2:
663 		/*
664 		 * reset the clock servo when offset is greater than the max
665 		 * offset value. Note that the clock jump will be performed in
666 		 * step 1, so it is not necessary to have clock jump
667 		 * immediately. This allows re-calculating drift as in initial
668 		 * clock startup.
669 		 */
670 		if (s->step_threshold &&
671 		    s->step_threshold < llabs(offset)) {
672 			*state = SERVO_UNLOCKED;
673 			s->count = 0;
674 			break;
675 		}
676 
677 		ki_term = KI * offset;
678 		ppb = KP * offset + s->drift + ki_term;
679 		if (ppb < -s->max_frequency)
680 			ppb = -s->max_frequency;
681 		else if (ppb > s->max_frequency)
682 			ppb = s->max_frequency;
683 		else
684 			s->drift += ki_term;
685 
686 		*state = SERVO_LOCKED;
687 		break;
688 	}
689 
690 	s->last_freq = ppb;
691 	return ppb;
692 }
693 
694 static void
695 ptp_adjust_servo(struct ptpv2_time_receiver_ordinary *ptp_data)
696 {
697 	uint64_t t1_ns, t2_ns;
698 	double adj_freq;
699 	enum servo_state state = SERVO_UNLOCKED;
700 
701 	t1_ns = timespec64_to_ns(&ptp_data->tstamp1);
702 	t2_ns = timespec64_to_ns(&ptp_data->tstamp2);
703 	ptp_data->master_offset = t2_ns - t1_ns - ptp_data->path_delay;
704 	if (!ptp_data->path_delay)
705 		return;
706 
707 	adj_freq = pi_sample(ptp_data->servo, ptp_data->master_offset, t2_ns,
708 		     &state);
709 
710 	switch (state) {
711 	case SERVO_UNLOCKED:
712 		break;
713 	case SERVO_JUMP:
714 		ptp_data->servo->first_update = 0;
715 		rte_eth_timesync_adjust_freq(ptp_data->portid,
716 						-(long)(adj_freq * 65.536));
717 		rte_eth_timesync_adjust_time(ptp_data->portid,
718 					     -ptp_data->master_offset);
719 		break;
720 	case SERVO_LOCKED:
721 		ptp_data->servo->first_update = 0;
722 		rte_eth_timesync_adjust_freq(ptp_data->portid,
723 					     -(long)(adj_freq * 65.536));
724 		break;
725 	}
726 }
727 
728 /*
729  * Parse the DELAY_RESP message.
730  */
731 static void
732 parse_drsp(struct ptpv2_time_receiver_ordinary *ptp_data)
733 {
734 	struct rte_mbuf *m = ptp_data->m;
735 	struct ptp_message *ptp_msg;
736 	struct tstamp *rx_tstamp;
737 	uint16_t seq_id;
738 
739 	ptp_msg = rte_pktmbuf_mtod_offset(m, struct ptp_message *,
740 					  sizeof(struct rte_ether_hdr));
741 	seq_id = rte_be_to_cpu_16(ptp_msg->delay_resp.hdr.seq_id);
742 	if (memcmp(&ptp_data->client_clock_id,
743 		   &ptp_msg->delay_resp.req_port_id.clock_id,
744 		   sizeof(struct clock_id)) == 0) {
745 		if (seq_id == ptp_data->seqID_FOLLOWUP) {
746 			rx_tstamp = &ptp_msg->delay_resp.rx_tstamp;
747 			ptp_data->tstamp4.tv_nsec = ntohl(rx_tstamp->ns);
748 			ptp_data->tstamp4.tv_sec =
749 				((uint64_t)ntohl(rx_tstamp->sec_lsb)) |
750 				(((uint64_t)ntohs(rx_tstamp->sec_msb)) << 32);
751 
752 			if (mode == MODE_PI) {
753 				clock_path_delay(ptp_data);
754 				ptp_adjust_servo(ptp_data);
755 			} else {
756 				/* Evaluate the delta for adjustment. */
757 				ptp_data->delta = delta_eval(ptp_data);
758 
759 				rte_eth_timesync_adjust_time(ptp_data->portid,
760 								ptp_data->delta);
761 			}
762 
763 			ptp_data->current_ptp_port = ptp_data->portid;
764 
765 			/* Update kernel time if enabled in app parameters. */
766 			if (ptp_data->kernel_time_set == 1)
767 				update_kernel_time();
768 
769 
770 
771 		}
772 	}
773 }
774 
775 /* This function processes PTP packets, implementing time receiver PTP IEEE1588 L2
776  * functionality.
777  */
778 
779 /* Parse ptp frames. 8< */
780 static void
781 parse_ptp_frames(uint16_t portid, struct rte_mbuf *m) {
782 	struct ptp_header *ptp_hdr;
783 	struct rte_ether_hdr *eth_hdr;
784 	uint16_t eth_type;
785 
786 	eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
787 	eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
788 
789 	if (eth_type == PTP_PROTOCOL) {
790 		ptp_data.m = m;
791 		ptp_data.portid = portid;
792 		ptp_hdr = rte_pktmbuf_mtod_offset(m, struct ptp_header *,
793 						  sizeof(struct rte_ether_hdr));
794 
795 		switch (ptp_hdr->msg_type) {
796 		case SYNC:
797 			parse_sync(&ptp_data, m->timesync);
798 			break;
799 		case FOLLOW_UP:
800 			parse_fup(&ptp_data);
801 			break;
802 		case DELAY_RESP:
803 			parse_drsp(&ptp_data);
804 			print_clock_info(&ptp_data);
805 			break;
806 		default:
807 			break;
808 		}
809 	}
810 }
811 /* >8 End of function processes PTP packets. */
812 
813 /*
814  * The lcore main. This is the main thread that does the work, reading from an
815  * input port and writing to an output port.
816  */
817 static void
818 lcore_main(void)
819 {
820 	uint16_t portid;
821 	unsigned nb_rx;
822 	struct rte_mbuf *m;
823 
824 	printf("\nCore %u Waiting for SYNC packets. [Ctrl+C to quit]\n",
825 			rte_lcore_id());
826 
827 	/* Run until the application is quit or killed. */
828 
829 	while (!force_quit) {
830 		/* Read packet from RX queues. 8< */
831 		for (portid = 0; portid < ptp_enabled_port_nb; portid++) {
832 
833 			portid = ptp_enabled_ports[portid];
834 			nb_rx = rte_eth_rx_burst(portid, 0, &m, 1);
835 
836 			if (likely(nb_rx == 0))
837 				continue;
838 
839 			/* Packet is parsed to determine which type. 8< */
840 			if (m->ol_flags & RTE_MBUF_F_RX_IEEE1588_PTP)
841 				parse_ptp_frames(portid, m);
842 			/* >8 End of packet is parsed to determine which type. */
843 
844 			rte_pktmbuf_free(m);
845 		}
846 		/* >8 End of read packets from RX queues. */
847 	}
848 }
849 
850 static void
851 print_usage(const char *prgname)
852 {
853 	printf("%s [EAL options] -- -p PORTMASK -T VALUE\n"
854 		" -T VALUE: 0 - Disable, 1 - Enable Linux Clock"
855 		" Synchronization (0 default)\n"
856 		" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
857 		" -c CONTROLLER: 0 - Not used, 1 - PI. The servo which is"
858 		" used to synchronize the local clock. (0 default)\n",
859 		prgname);
860 }
861 
862 static int
863 ptp_parse_portmask(const char *portmask)
864 {
865 	char *end = NULL;
866 	unsigned long pm;
867 
868 	/* Parse the hexadecimal string. */
869 	pm = strtoul(portmask, &end, 16);
870 
871 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
872 		return 0;
873 
874 	return pm;
875 }
876 
877 static int
878 parse_ptp_kernel(const char *param)
879 {
880 	char *end = NULL;
881 	unsigned long pm;
882 
883 	/* Parse the hexadecimal string. */
884 	pm = strtoul(param, &end, 16);
885 
886 	if ((param[0] == '\0') || (end == NULL) || (*end != '\0'))
887 		return -1;
888 	if (pm == 0)
889 		return 0;
890 
891 	return 1;
892 }
893 
894 static int
895 parse_ptp_servo_mode(const char *param)
896 {
897 	char *end = NULL;
898 	unsigned long pm;
899 
900 	/* Parse the hexadecimal string. */
901 	pm = strtoul(param, &end, 10);
902 
903 	if ((param[0] == '\0') || (end == NULL) || (*end != '\0'))
904 		return -1;
905 
906 	return pm;
907 }
908 
909 static void
910 servo_init(struct pi_servo *servo)
911 {
912 	memset(servo, 0x00, sizeof(*servo));
913 
914 	servo->drift = 100000000;
915 	servo->last_freq = 100000000;
916 	servo->count = 0;
917 
918 	servo->max_frequency = 100000000;
919 	servo->step_threshold = 0.1 * NSEC_PER_SEC;
920 	servo->first_step_threshold = 0.00002 * NSEC_PER_SEC;
921 	servo->first_update = 1;
922 }
923 
924 /* Parse the commandline arguments. */
925 static int
926 ptp_parse_args(int argc, char **argv)
927 {
928 	int opt, ret;
929 	char **argvopt;
930 	int option_index;
931 	char *prgname = argv[0];
932 	static struct option lgopts[] = { {NULL, 0, 0, 0} };
933 
934 	argvopt = argv;
935 
936 	while ((opt = getopt_long(argc, argvopt, "p:T:c:",
937 				  lgopts, &option_index)) != EOF) {
938 
939 		switch (opt) {
940 
941 		/* Portmask. */
942 		case 'p':
943 			ptp_enabled_port_mask = ptp_parse_portmask(optarg);
944 			if (ptp_enabled_port_mask == 0) {
945 				printf("invalid portmask\n");
946 				print_usage(prgname);
947 				return -1;
948 			}
949 			break;
950 		/* Time synchronization. */
951 		case 'T':
952 			ret = parse_ptp_kernel(optarg);
953 			if (ret < 0) {
954 				print_usage(prgname);
955 				return -1;
956 			}
957 
958 			ptp_data.kernel_time_set = ret;
959 			break;
960 		case 'c':
961 			ret = parse_ptp_servo_mode(optarg);
962 			if (ret == 0) {
963 				mode = MODE_NONE;
964 			} else if (ret == 1) {
965 				mode = MODE_PI;
966 			} else {
967 				print_usage(prgname);
968 				return -1;
969 			}
970 			break;
971 
972 		default:
973 			print_usage(prgname);
974 			return -1;
975 		}
976 	}
977 
978 	argv[optind-1] = prgname;
979 
980 	optind = 1; /* Reset getopt lib. */
981 
982 	return 0;
983 }
984 
985 static void
986 signal_handler(int signum)
987 {
988 	if (signum == SIGINT || signum == SIGTERM)
989 		force_quit = true;
990 }
991 
992 /*
993  * The main function, which does initialization and calls the per-lcore
994  * functions.
995  */
996 int
997 main(int argc, char *argv[])
998 {
999 	unsigned nb_ports;
1000 
1001 	uint16_t portid;
1002 
1003 	/* Initialize the Environment Abstraction Layer (EAL). 8< */
1004 	int ret = rte_eal_init(argc, argv);
1005 
1006 	if (ret < 0)
1007 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
1008 	/* >8 End of initialization of EAL. */
1009 
1010 	memset(&ptp_data, 0, sizeof(struct ptpv2_time_receiver_ordinary));
1011 
1012 	/* Parse specific arguments. 8< */
1013 	argc -= ret;
1014 	argv += ret;
1015 
1016 	force_quit = false;
1017 	signal(SIGINT, signal_handler);
1018 	signal(SIGTERM, signal_handler);
1019 
1020 	ret = ptp_parse_args(argc, argv);
1021 	if (ret < 0)
1022 		rte_exit(EXIT_FAILURE, "Error with PTP initialization\n");
1023 	/* >8 End of parsing specific arguments. */
1024 
1025 	if (mode == MODE_PI) {
1026 		ptp_data.servo = malloc(sizeof(*(ptp_data.servo)));
1027 		if (!ptp_data.servo)
1028 			rte_exit(EXIT_FAILURE, "no memory for servo\n");
1029 
1030 		servo_init(ptp_data.servo);
1031 	}
1032 
1033 	/* Check that there is an even number of ports to send/receive on. */
1034 	nb_ports = rte_eth_dev_count_avail();
1035 
1036 	/* Creates a new mempool in memory to hold the mbufs. 8< */
1037 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
1038 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
1039 	/* >8 End of a new mempool in memory to hold the mbufs. */
1040 
1041 	if (mbuf_pool == NULL)
1042 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
1043 
1044 	/* Initialize all ports. 8< */
1045 	RTE_ETH_FOREACH_DEV(portid) {
1046 		if ((ptp_enabled_port_mask & (1 << portid)) != 0) {
1047 			if (port_init(portid, mbuf_pool) == 0) {
1048 				ptp_enabled_ports[ptp_enabled_port_nb] = portid;
1049 				ptp_enabled_port_nb++;
1050 			} else {
1051 				rte_exit(EXIT_FAILURE,
1052 					 "Cannot init port %"PRIu8 "\n",
1053 					 portid);
1054 			}
1055 		} else
1056 			printf("Skipping disabled port %u\n", portid);
1057 	}
1058 	/* >8 End of initialization of all ports. */
1059 
1060 	if (ptp_enabled_port_nb == 0) {
1061 		rte_exit(EXIT_FAILURE,
1062 			"All available ports are disabled."
1063 			" Please set portmask.\n");
1064 	}
1065 
1066 	if (rte_lcore_count() > 1)
1067 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
1068 
1069 	/* Call lcore_main on the main core only. */
1070 	lcore_main();
1071 
1072 	RTE_ETH_FOREACH_DEV(portid) {
1073 		if ((ptp_enabled_port_mask & (1 << portid)) == 0)
1074 			continue;
1075 
1076 		/* Disable timesync timestamping for the Ethernet device */
1077 		rte_eth_timesync_disable(portid);
1078 
1079 		ret = rte_eth_dev_stop(portid);
1080 		if (ret != 0)
1081 			printf("rte_eth_dev_stop: err=%d, port=%d\n", ret, portid);
1082 
1083 		rte_eth_dev_close(portid);
1084 	}
1085 
1086 	if (mode == MODE_PI)
1087 		free(ptp_data.servo);
1088 
1089 	/* clean up the EAL */
1090 	rte_eal_cleanup();
1091 
1092 	return 0;
1093 }
1094