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