Re: [dpdk-dev] [PATCH] net/pcap: support hardware Tx timestamps
Hi Olivier, On Thu, 25 Jun 2020 18:35:32 +0200, Olivier Matz wrote: > As said by Ferruh, the unit of timestamp in mbuf is not normalized to > nanosecs, as seen in rte_mbuf_core.h: > > /** Valid if PKT_RX_TIMESTAMP is set. The unit and time reference >* are not normalized but are always the same for a given port. >* Some devices allow to query rte_eth_read_clock that will return the >* current device timestamp. >*/ > uint64_t timestamp; > > Using the timestamp generated from a port which is not a pmd-pcap would > require a conversion, using rte_eth_read_clock() on mbuf->port (assuming > it was not modified, which should be true except if event eth Tx adapter > is used). > > Also, note that the timestamp corresponds to the Rx timestamp. I think it > could be an issue in case the mbuf is reassembled by the application: the > timestamp in reassembled mbuf would be the one from the first fragment. > > So, I share Ferruh's concerns. I think this is not totally true depending on the driver. For instance, we use mlx5 which already provides a timestamp conversion to nanosecs through libibverbs. Let me resend this patch alongside Patrick's mlx5 patches that implemented the needed glue, so that you may understand better the big picture of how we enabled hardware timestamping in PCAP capture using mlx5 and pdump. Regards, Vivien
[dpdk-dev] [RFC PATCH 0/3] mlx5 to PCAP capture with hardware timestamps
This series allows to capture packets from a Mellanox ConnectX-5 interface into a PCAP file with support for hardware timestamps. Since libibverbs already provides timestamp conversion to nanoseconds for mlx5, the necessary glue is added before writing the driver's timestamps into the PCAP headers. Patrick Keroulas (2): net/mlx5: add timestamp-to-ns converter from libibverbs ethdev: add API to convert raw timestamps to nsec Vivien Didelot (1): net/pcap: support hardware Tx timestamps doc/guides/rel_notes/release_20_08.rst | 1 + drivers/common/mlx5/linux/mlx5_glue.c| 16 + drivers/common/mlx5/linux/mlx5_glue.h| 4 drivers/net/mlx5/linux/mlx5_ethdev_os.c | 30 drivers/net/mlx5/linux/mlx5_os.c | 1 + drivers/net/mlx5/mlx5.h | 1 + drivers/net/pcap/rte_eth_pcap.c | 30 ++-- lib/librte_ethdev/rte_ethdev.c | 12 ++ lib/librte_ethdev/rte_ethdev.h | 17 ++ lib/librte_ethdev/rte_ethdev_core.h | 5 lib/librte_ethdev/rte_ethdev_version.map | 2 ++ lib/librte_mbuf/rte_mbuf_core.h | 3 ++- lib/librte_pdump/rte_pdump.c | 14 ++- 13 files changed, 121 insertions(+), 15 deletions(-) -- 2.27.0
[dpdk-dev] [RFC PATCH 2/3] ethdev: add API to convert raw timestamps to nsec
From: Patrick Keroulas Existing ethdev functions can read/write time from/to device but they're all related to timesync and none of them can translate a raw counter in real time unit which is useful in a pdump application. A new API is required because the conversion is derived from dev clock info. Signed-off-by: Patrick Keroulas --- lib/librte_ethdev/rte_ethdev.c | 12 lib/librte_ethdev/rte_ethdev.h | 17 + lib/librte_ethdev/rte_ethdev_core.h | 5 + lib/librte_ethdev/rte_ethdev_version.map | 2 ++ lib/librte_mbuf/rte_mbuf_core.h | 3 ++- lib/librte_pdump/rte_pdump.c | 14 +- 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 8e10a6fc3..822fa6d5a 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -4810,6 +4810,18 @@ rte_eth_timesync_write_time(uint16_t port_id, const struct timespec *timestamp) timestamp)); } +int +rte_eth_convert_ts_to_ns(uint16_t port_id, uint64_t *timestamp) +{ + struct rte_eth_dev *dev; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV); + dev = &rte_eth_devices[port_id]; + + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->convert_ts_to_ns, -ENOTSUP); + return eth_err(port_id, (*dev->dev_ops->convert_ts_to_ns)(dev, timestamp)); +} + int rte_eth_read_clock(uint16_t port_id, uint64_t *clock) { diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index a49242bcd..2d4d0bc7d 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -4103,6 +4103,23 @@ int rte_eth_timesync_read_time(uint16_t port_id, struct timespec *time); */ int rte_eth_timesync_write_time(uint16_t port_id, const struct timespec *time); +/** + * Convert a raw clock counter to nanoseconds from device clock + * + * @param port_id + * The port identifier of the Ethernet device. + * @param[in&out] timestamp + * Pointer to the timestamp to be converted. + * + * @return + * - 0: Success. + * - -ENODEV: The port ID is invalid. + * - -ENOTSUP: The function is not supported by the Ethernet driver. + */ +__rte_experimental +int +rte_eth_convert_ts_to_ns(uint16_t port_id, uint64_t *timestamp); + /** * @warning * @b EXPERIMENTAL: this API may change without prior notice. diff --git a/lib/librte_ethdev/rte_ethdev_core.h b/lib/librte_ethdev/rte_ethdev_core.h index 32407dd41..255b41b67 100644 --- a/lib/librte_ethdev/rte_ethdev_core.h +++ b/lib/librte_ethdev/rte_ethdev_core.h @@ -464,6 +464,10 @@ typedef int (*eth_timesync_write_time)(struct rte_eth_dev *dev, const struct timespec *timestamp); /**< @internal Function used to get time from the device clock */ +typedef int (*eth_convert_ts_to_ns)(struct rte_eth_dev *dev, + uint64_t *timestamp); +/**< @internal Function used to convert timestamp from device clock */ + typedef int (*eth_read_clock)(struct rte_eth_dev *dev, uint64_t *timestamp); /**< @internal Function used to get the current value of the device clock. */ @@ -730,6 +734,7 @@ struct eth_dev_ops { eth_timesync_read_time timesync_read_time; /** Get the device clock time. */ eth_timesync_write_timetimesync_write_time; /** Set the device clock time. */ + eth_convert_ts_to_ns convert_ts_to_ns; eth_read_clock read_clock; eth_xstats_get_by_id_t xstats_get_by_id; diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index 715505604..754c05630 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -241,4 +241,6 @@ EXPERIMENTAL { __rte_ethdev_trace_rx_burst; __rte_ethdev_trace_tx_burst; rte_flow_get_aged_flows; + + rte_eth_convert_ts_to_ns; }; diff --git a/lib/librte_mbuf/rte_mbuf_core.h b/lib/librte_mbuf/rte_mbuf_core.h index 16600f171..470616fb2 100644 --- a/lib/librte_mbuf/rte_mbuf_core.h +++ b/lib/librte_mbuf/rte_mbuf_core.h @@ -595,7 +595,8 @@ struct rte_mbuf { /** Valid if PKT_RX_TIMESTAMP is set. The unit and time reference * are not normalized but are always the same for a given port. * Some devices allow to query rte_eth_read_clock that will return the -* current device timestamp. +* current device timestamp or rte_eth_ts_to_ns that will convert raw +* counter to nanoseconds. */ uint64_t timestamp; diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c index f96709f95..03d9ba484 100644 --- a/lib/librte_pdump/rte_pdump.c +++ b/lib/librte_pdump/rte_pdump.c @@ -100,12 +100,24 @@ pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
[dpdk-dev] [RFC PATCH 1/3] net/mlx5: add timestamp-to-ns converter from libibverbs
From: Patrick Keroulas While some devices update their own clock info to provide current time, mlx5dv part of libibverbs already handles this and also converts any raw counter cycle to nanoseconds. Signed-off-by: Patrick Keroulas --- drivers/common/mlx5/linux/mlx5_glue.c | 16 + drivers/common/mlx5/linux/mlx5_glue.h | 4 drivers/net/mlx5/linux/mlx5_ethdev_os.c | 30 + drivers/net/mlx5/linux/mlx5_os.c| 1 + drivers/net/mlx5/mlx5.h | 1 + 5 files changed, 52 insertions(+) diff --git a/drivers/common/mlx5/linux/mlx5_glue.c b/drivers/common/mlx5/linux/mlx5_glue.c index c91ee33bb..cac24015b 100644 --- a/drivers/common/mlx5/linux/mlx5_glue.c +++ b/drivers/common/mlx5/linux/mlx5_glue.c @@ -80,6 +80,20 @@ mlx5_glue_query_rt_values_ex(struct ibv_context *context, return ibv_query_rt_values_ex(context, values); } +static int +mlx5_glue_get_clock_info(struct ibv_context *context, + struct mlx5dv_clock_info *clock_info) +{ + return mlx5dv_get_clock_info(context, clock_info); +} + +static uint64_t +mlx5_glue_mlx5dv_ts_to_ns(struct mlx5dv_clock_info *clock_info, + uint64_t device_timestamp) +{ + return mlx5dv_ts_to_ns(clock_info, device_timestamp); +} + static int mlx5_glue_query_port(struct ibv_context *context, uint8_t port_num, struct ibv_port_attr *port_attr) @@ -1207,6 +1221,8 @@ const struct mlx5_glue *mlx5_glue = &(const struct mlx5_glue) { .query_device = mlx5_glue_query_device, .query_device_ex = mlx5_glue_query_device_ex, .query_rt_values_ex = mlx5_glue_query_rt_values_ex, + .get_clock_info = mlx5_glue_get_clock_info, + .convert_ts_to_ns = mlx5_glue_mlx5dv_ts_to_ns, .query_port = mlx5_glue_query_port, .create_comp_channel = mlx5_glue_create_comp_channel, .destroy_comp_channel = mlx5_glue_destroy_comp_channel, diff --git a/drivers/common/mlx5/linux/mlx5_glue.h b/drivers/common/mlx5/linux/mlx5_glue.h index 5d238a40a..8d05e7398 100644 --- a/drivers/common/mlx5/linux/mlx5_glue.h +++ b/drivers/common/mlx5/linux/mlx5_glue.h @@ -123,6 +123,10 @@ struct mlx5_glue { struct ibv_port_attr *port_attr); struct ibv_comp_channel *(*create_comp_channel) (struct ibv_context *context); + int (*get_clock_info)(struct ibv_context *context, + struct mlx5dv_clock_info *clock_info); + uint64_t (*convert_ts_to_ns)(struct mlx5dv_clock_info *clock_info, + uint64_t device_timestamp); int (*destroy_comp_channel)(struct ibv_comp_channel *channel); struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe, void *cq_context, diff --git a/drivers/net/mlx5/linux/mlx5_ethdev_os.c b/drivers/net/mlx5/linux/mlx5_ethdev_os.c index ab47cb531..86bec111b 100644 --- a/drivers/net/mlx5/linux/mlx5_ethdev_os.c +++ b/drivers/net/mlx5/linux/mlx5_ethdev_os.c @@ -355,6 +355,36 @@ mlx5_set_flags(struct rte_eth_dev *dev, unsigned int keep, unsigned int flags) return mlx5_ifreq(dev, SIOCSIFFLAGS, &request); } +/** + * Convert raw clock counter to nanoseconds + * + * @param dev + * Pointer to Ethernet device structure. + * @param[in&out] timestamp + * Pointer to the timestamp to be converted. + * + * @return + * 0 if the clock has correctly been read + * The value of errno in case of error + */ +int +mlx5_convert_ts_to_ns(struct rte_eth_dev *dev, uint64_t *timestamp) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct ibv_context *ctx = priv->sh->ctx; + struct mlx5dv_clock_info clock_info; + + int err = mlx5_glue->get_clock_info(ctx, &clock_info); + if (err != 0) { + DRV_LOG(WARNING, "Could not get the clock info!"); + return err; + } + + *timestamp = mlx5_glue->convert_ts_to_ns(&clock_info, *timestamp); + + return err; +} + /** * Get device current raw clock counter * diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index 3792371c3..914e58f52 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -2408,6 +2408,7 @@ const struct eth_dev_ops mlx5_os_dev_sec_ops = { .xstats_get_names = mlx5_xstats_get_names, .fw_version_get = mlx5_fw_version_get, .dev_infos_get = mlx5_dev_infos_get, + .convert_ts_to_ns = mlx5_convert_ts_to_ns, .rx_descriptor_status = mlx5_rx_descriptor_status, .tx_descriptor_status = mlx5_tx_descriptor_status, .rxq_info_get = mlx5_rxq_info_get, diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 5bd5acd9d..dc469f7d9 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -738,6 +738,7 @@ int mlx5_get_mtu(struct rte_eth_dev *dev, uint16_t *mtu); int mlx5_set_flags(struct rte_eth_dev *dev,
[dpdk-dev] [RFC PATCH 3/3] net/pcap: support hardware Tx timestamps
When hardware timestamping is enabled on Rx path, system time should no longer be used to calculate the timestamps when dumping packets. Instead, use the value stored by the driver in mbuf->timestamp and assume it is already converted to nanoseconds (otherwise the application may edit the packet headers itself afterwards). Signed-off-by: Vivien Didelot Signed-off-by: Patrick Keroulas --- doc/guides/rel_notes/release_20_08.rst | 1 + drivers/net/pcap/rte_eth_pcap.c| 30 +++--- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/guides/rel_notes/release_20_08.rst b/doc/guides/rel_notes/release_20_08.rst index a67015519..cd1ca987f 100644 --- a/doc/guides/rel_notes/release_20_08.rst +++ b/doc/guides/rel_notes/release_20_08.rst @@ -61,6 +61,7 @@ New Features Updated PCAP driver with new features and improvements, including: * Support software Tx nanosecond timestamps precision. + * Support hardware Tx timestamps. * **Updated Mellanox mlx5 driver.** diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c index 13a3d0ac7..3d80b699b 100644 --- a/drivers/net/pcap/rte_eth_pcap.c +++ b/drivers/net/pcap/rte_eth_pcap.c @@ -290,19 +290,23 @@ eth_null_rx(void *queue __rte_unused, #define NSEC_PER_SEC 10L static inline void -calculate_timestamp(struct timeval *ts) { - uint64_t cycles; - struct timeval cur_time; +calculate_timestamp(const struct rte_mbuf *mbuf, struct timeval *ts) { + if (mbuf->ol_flags & PKT_RX_TIMESTAMP) { + ts->tv_sec = mbuf->timestamp / NSEC_PER_SEC; + ts->tv_usec = mbuf->timestamp % NSEC_PER_SEC; + } else { + uint64_t cycles = rte_get_timer_cycles() - start_cycles; + struct timeval cur_time = { + .tv_sec = cycles / hz, + .tv_usec = (cycles % hz) * NSEC_PER_SEC / hz, + }; - cycles = rte_get_timer_cycles() - start_cycles; - cur_time.tv_sec = cycles / hz; - cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz; - - ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; - ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; - if (ts->tv_usec >= NSEC_PER_SEC) { - ts->tv_usec -= NSEC_PER_SEC; - ts->tv_sec += 1; + ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; + ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; + if (ts->tv_usec >= NSEC_PER_SEC) { + ts->tv_usec -= NSEC_PER_SEC; + ts->tv_sec += 1; + } } } @@ -339,7 +343,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) caplen = sizeof(temp_data); } - calculate_timestamp(&header.ts); + calculate_timestamp(mbuf, &header.ts); header.len = len; header.caplen = caplen; /* rte_pktmbuf_read() returns a pointer to the data directly -- 2.27.0
[dpdk-dev] [PATCH 2/2] net/pcap: add TODO for writing Tx HW timestamp
In order to write a packet with hardware timestamp enabled into a PCAP file, we need to convert its device specific raw timestamp first. This might not be trivial since querying the raw clock value from the device is still experimental, and derivating the frequency would ideally require an additional alarm thread. As a first step, pass the mbuf to the timestamp calculation function since mbuf->port and mbuf->timestamp would be needed, and add a TODO note. No functional changes. Signed-off-by: Vivien Didelot --- drivers/net/pcap/rte_eth_pcap.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c index 68588c3d7..f205a28e0 100644 --- a/drivers/net/pcap/rte_eth_pcap.c +++ b/drivers/net/pcap/rte_eth_pcap.c @@ -290,10 +290,16 @@ eth_null_rx(void *queue __rte_unused, #define NSEC_PER_SEC 1e9 static inline void -calculate_timestamp(struct timeval *ts) { +calculate_timestamp(const struct rte_mbuf *mbuf, struct timeval *ts) { uint64_t cycles; struct timeval cur_time; + if (mbuf->ol_flags & PKT_RX_TIMESTAMP) { + /* TODO: convert mbuf->timestamp into nanoseconds instead. + * See rte_eth_read_clock(). + */ + } + cycles = rte_get_timer_cycles() - start_cycles; cur_time.tv_sec = cycles / hz; cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz; @@ -339,7 +345,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) caplen = sizeof(temp_data); } - calculate_timestamp(&header.ts); + calculate_timestamp(mbuf, &header.ts); header.len = len; header.caplen = caplen; /* rte_pktmbuf_read() returns a pointer to the data directly -- 2.26.2
[dpdk-dev] [PATCH 1/2] net/pcap: support software Tx nanosecond timestamp
When capturing packets into a PCAP file, DPDK currently uses microseconds for the timestamp. But libpcap supports interpreting tv_usec as nanoseconds depending on the file timestamp precision. To support this, use PCAP_TSTAMP_PRECISION_NANO when creating the empty PCAP file as specified by PCAP_OPEN_DEAD(3PCAP) and implement nanosecond timeval addition. This also ensures that the precision reported by capinfos is nanoseconds (9). Signed-off-by: Vivien Didelot --- drivers/net/pcap/rte_eth_pcap.c | 15 --- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c index b4c79d174..68588c3d7 100644 --- a/drivers/net/pcap/rte_eth_pcap.c +++ b/drivers/net/pcap/rte_eth_pcap.c @@ -287,6 +287,8 @@ eth_null_rx(void *queue __rte_unused, return 0; } +#define NSEC_PER_SEC 1e9 + static inline void calculate_timestamp(struct timeval *ts) { uint64_t cycles; @@ -294,8 +296,14 @@ calculate_timestamp(struct timeval *ts) { cycles = rte_get_timer_cycles() - start_cycles; cur_time.tv_sec = cycles / hz; - cur_time.tv_usec = (cycles % hz) * 1e6 / hz; - timeradd(&start_time, &cur_time, ts); + cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz; + + ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; + ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; + if (ts->tv_usec > NSEC_PER_SEC) { + ts->tv_usec -= NSEC_PER_SEC; + ts->tv_sec += 1; + } } /* @@ -475,7 +483,8 @@ open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper) * with pcap_dump_open(). We create big enough an Ethernet * pcap holder. */ - tx_pcap = pcap_open_dead(DLT_EN10MB, RTE_ETH_PCAP_SNAPSHOT_LEN); + tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, + RTE_ETH_PCAP_SNAPSHOT_LEN, PCAP_TSTAMP_PRECISION_NANO); if (tx_pcap == NULL) { PMD_LOG(ERR, "Couldn't create dead pcap"); return -1; -- 2.26.2
[dpdk-dev] [PATCH v2] net/pcap: support software Tx nanosecond timestamps
When capturing packets into a PCAP file, DPDK currently uses microseconds for the timestamps. But libpcap supports interpreting tv_usec as nanoseconds depending on the file timestamp precision, as of commit ba89e4a18e8b ("Make timestamps precision configurable"). To support this, use PCAP_TSTAMP_PRECISION_NANO when creating the empty PCAP file as specified by PCAP_OPEN_DEAD(3PCAP) and implement nanosecond timeval addition. This also ensures that the precision reported by capinfos is nanoseconds (9). Note that NSEC_PER_SEC is defined as 10L instead of 1e9 since the latter might be interpreted as floating point. Signed-off-by: Vivien Didelot --- doc/guides/rel_notes/release_20_08.rst | 6 ++ drivers/net/pcap/rte_eth_pcap.c| 15 --- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/doc/guides/rel_notes/release_20_08.rst b/doc/guides/rel_notes/release_20_08.rst index dee4ccbb5..7a67c960c 100644 --- a/doc/guides/rel_notes/release_20_08.rst +++ b/doc/guides/rel_notes/release_20_08.rst @@ -56,6 +56,12 @@ New Features Also, make sure to start the actual text at the margin. = +* **Updated PCAP driver.** + + Updated PCAP driver with new features and improvements, including: + + * Support software Tx nanosecond timestamps precision. + * **Updated Mellanox mlx5 driver.** Updated Mellanox mlx5 driver with new features and improvements, including: diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c index b4c79d174..13a3d0ac7 100644 --- a/drivers/net/pcap/rte_eth_pcap.c +++ b/drivers/net/pcap/rte_eth_pcap.c @@ -287,6 +287,8 @@ eth_null_rx(void *queue __rte_unused, return 0; } +#define NSEC_PER_SEC 10L + static inline void calculate_timestamp(struct timeval *ts) { uint64_t cycles; @@ -294,8 +296,14 @@ calculate_timestamp(struct timeval *ts) { cycles = rte_get_timer_cycles() - start_cycles; cur_time.tv_sec = cycles / hz; - cur_time.tv_usec = (cycles % hz) * 1e6 / hz; - timeradd(&start_time, &cur_time, ts); + cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz; + + ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; + ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; + if (ts->tv_usec >= NSEC_PER_SEC) { + ts->tv_usec -= NSEC_PER_SEC; + ts->tv_sec += 1; + } } /* @@ -475,7 +483,8 @@ open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper) * with pcap_dump_open(). We create big enough an Ethernet * pcap holder. */ - tx_pcap = pcap_open_dead(DLT_EN10MB, RTE_ETH_PCAP_SNAPSHOT_LEN); + tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, + RTE_ETH_PCAP_SNAPSHOT_LEN, PCAP_TSTAMP_PRECISION_NANO); if (tx_pcap == NULL) { PMD_LOG(ERR, "Couldn't create dead pcap"); return -1; -- 2.27.0
Re: [dpdk-dev] [PATCH v2] net/pcap: support software Tx nanosecond timestamps
Hi Stephen, On Tue, 9 Jun 2020 12:43:57 -0700, Stephen Hemminger wrote: > On Tue, 9 Jun 2020 15:07:19 -0400 > Vivien Didelot wrote: > > > > > +#define NSEC_PER_SEC 10L > > + > > static inline void > > calculate_timestamp(struct timeval *ts) { > > uint64_t cycles; > > @@ -294,8 +296,14 @@ calculate_timestamp(struct timeval *ts) { > > > > cycles = rte_get_timer_cycles() - start_cycles; > > cur_time.tv_sec = cycles / hz; > > - cur_time.tv_usec = (cycles % hz) * 1e6 / hz; > > - timeradd(&start_time, &cur_time, ts); > > + cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz; > > + > > + ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; > > + ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; > > + if (ts->tv_usec >= NSEC_PER_SEC) { > > + ts->tv_usec -= NSEC_PER_SEC; > > + ts->tv_sec += 1; > > + } > > } > > > > You may want to pre-compute the reciprocal here to save the expensive > cost of divide in the fast path. See rte_reciprocal. Please note that I did not change the calculation logic that was previously used here. Thus pre-computing the reciprocal here to save the expensive cost of divide in the fast path seems out of the scope of this patch to me. Can we keep this for a future patch maybe? Thanks, Vivien
[dpdk-dev] [PATCH] net/pcap: support hardware Tx timestamps
When hardware timestamping is enabled on Rx path, system time should no longer be used to calculate the timestamps when dumping packets. Instead, use the value stored by the driver in mbuf->timestamp and assume it is already converted to nanoseconds (otherwise the application may edit the packet headers itself afterwards). Signed-off-by: Vivien Didelot Signed-off-by: Patrick Keroulas --- doc/guides/rel_notes/release_20_08.rst | 1 + drivers/net/pcap/rte_eth_pcap.c| 30 +++--- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/doc/guides/rel_notes/release_20_08.rst b/doc/guides/rel_notes/release_20_08.rst index 7a67c960c..cedceaf9d 100644 --- a/doc/guides/rel_notes/release_20_08.rst +++ b/doc/guides/rel_notes/release_20_08.rst @@ -61,6 +61,7 @@ New Features Updated PCAP driver with new features and improvements, including: * Support software Tx nanosecond timestamps precision. + * Support hardware Tx timestamps. * **Updated Mellanox mlx5 driver.** diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c index 13a3d0ac7..3d80b699b 100644 --- a/drivers/net/pcap/rte_eth_pcap.c +++ b/drivers/net/pcap/rte_eth_pcap.c @@ -290,19 +290,23 @@ eth_null_rx(void *queue __rte_unused, #define NSEC_PER_SEC 10L static inline void -calculate_timestamp(struct timeval *ts) { - uint64_t cycles; - struct timeval cur_time; +calculate_timestamp(const struct rte_mbuf *mbuf, struct timeval *ts) { + if (mbuf->ol_flags & PKT_RX_TIMESTAMP) { + ts->tv_sec = mbuf->timestamp / NSEC_PER_SEC; + ts->tv_usec = mbuf->timestamp % NSEC_PER_SEC; + } else { + uint64_t cycles = rte_get_timer_cycles() - start_cycles; + struct timeval cur_time = { + .tv_sec = cycles / hz, + .tv_usec = (cycles % hz) * NSEC_PER_SEC / hz, + }; - cycles = rte_get_timer_cycles() - start_cycles; - cur_time.tv_sec = cycles / hz; - cur_time.tv_usec = (cycles % hz) * NSEC_PER_SEC / hz; - - ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; - ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; - if (ts->tv_usec >= NSEC_PER_SEC) { - ts->tv_usec -= NSEC_PER_SEC; - ts->tv_sec += 1; + ts->tv_sec = start_time.tv_sec + cur_time.tv_sec; + ts->tv_usec = start_time.tv_usec + cur_time.tv_usec; + if (ts->tv_usec >= NSEC_PER_SEC) { + ts->tv_usec -= NSEC_PER_SEC; + ts->tv_sec += 1; + } } } @@ -339,7 +343,7 @@ eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) caplen = sizeof(temp_data); } - calculate_timestamp(&header.ts); + calculate_timestamp(mbuf, &header.ts); header.len = len; header.caplen = caplen; /* rte_pktmbuf_read() returns a pointer to the data directly -- 2.27.0
Re: [dpdk-dev] [PATCH] net/pcap: support hardware Tx timestamps
Hi Ferruh, On Wed, 10 Jun 2020 15:39:38 -0400, Vivien Didelot wrote: > When hardware timestamping is enabled on Rx path, system time should > no longer be used to calculate the timestamps when dumping packets. > > Instead, use the value stored by the driver in mbuf->timestamp > and assume it is already converted to nanoseconds (otherwise the > application may edit the packet headers itself afterwards). > > Signed-off-by: Vivien Didelot > Signed-off-by: Patrick Keroulas Any feedback on this patch? Thank you, Vivien
Re: [dpdk-dev] [PATCH] net/pcap: support hardware Tx timestamps
Hi Oliver, Surprisingly, dumping PCAP with hardware timestamps seems to be a niche, but we do need this feature for our network analyzing tool. Do you guys have objections for this patch? Regards, Vivien On Wed, Jun 17, 2020 at 4:16 AM Ferruh Yigit wrote: > On 6/10/2020 8:39 PM, Vivien Didelot wrote: > > When hardware timestamping is enabled on Rx path, system time should > > no longer be used to calculate the timestamps when dumping packets. > > > > Instead, use the value stored by the driver in mbuf->timestamp > > and assume it is already converted to nanoseconds (otherwise the > > application may edit the packet headers itself afterwards). > > > > Signed-off-by: Vivien Didelot > > Signed-off-by: Patrick Keroulas > > --- > > doc/guides/rel_notes/release_20_08.rst | 1 + > > drivers/net/pcap/rte_eth_pcap.c| 30 +++--- > > 2 files changed, 18 insertions(+), 13 deletions(-) > > > > diff --git a/doc/guides/rel_notes/release_20_08.rst > b/doc/guides/rel_notes/release_20_08.rst > > index 7a67c960c..cedceaf9d 100644 > > --- a/doc/guides/rel_notes/release_20_08.rst > > +++ b/doc/guides/rel_notes/release_20_08.rst > > @@ -61,6 +61,7 @@ New Features > >Updated PCAP driver with new features and improvements, including: > > > >* Support software Tx nanosecond timestamps precision. > > + * Support hardware Tx timestamps. > > > > * **Updated Mellanox mlx5 driver.** > > > > diff --git a/drivers/net/pcap/rte_eth_pcap.c > b/drivers/net/pcap/rte_eth_pcap.c > > index 13a3d0ac7..3d80b699b 100644 > > --- a/drivers/net/pcap/rte_eth_pcap.c > > +++ b/drivers/net/pcap/rte_eth_pcap.c > > @@ -290,19 +290,23 @@ eth_null_rx(void *queue __rte_unused, > > #define NSEC_PER_SEC 10L > > > > static inline void > > -calculate_timestamp(struct timeval *ts) { > > - uint64_t cycles; > > - struct timeval cur_time; > > +calculate_timestamp(const struct rte_mbuf *mbuf, struct timeval *ts) { > > + if (mbuf->ol_flags & PKT_RX_TIMESTAMP) { > > + ts->tv_sec = mbuf->timestamp / NSEC_PER_SEC; > > + ts->tv_usec = mbuf->timestamp % NSEC_PER_SEC; > > Hi Vivien, > > No objection from pcap PMD point of view. > > But should we have a Tx mbuf flag, 'PKT_TX_TIMESTAMP', for applications to > request drivers to use the timestamp field on Tx path? Not sure if there > can be > any problem on using Rx flag on both direction? > > Also the metric is not defined for the 'mbuf->timestamp', it doesn't need > to be > nanoseconds, not sure if it is correct to assume it is. Or should we > define a > metric for timestamp on the Tx path? > > cc'ed Oliver, I think he can comment better on above two questions. > > Thanks, > ferruh > >