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