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