net-timestamp: introduce SOF_TIMESTAMPING_OPT_RX_FILTER flag

introduce a new flag SOF_TIMESTAMPING_OPT_RX_FILTER in the receive
path. User can set it with SOF_TIMESTAMPING_SOFTWARE to filter
out rx software timestamp report, especially after a process turns on
netstamp_needed_key which can time stamp every incoming skb.

Previously, we found out if an application starts first which turns on
netstamp_needed_key, then another one only passing SOF_TIMESTAMPING_SOFTWARE
could also get rx timestamp. Now we handle this case by introducing this
new flag without breaking users.

Quoting Willem to explain why we need the flag:
"why a process would want to request software timestamp reporting, but
not receive software timestamp generation. The only use I see is when
the application does request
SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_TX_SOFTWARE."

Similarly, this new flag could also be used for hardware case where we
can set it with SOF_TIMESTAMPING_RAW_HARDWARE, then we won't receive
hardware receive timestamp.

Another thing about errqueue in this patch I have a few words to say:
In this case, we need to handle the egress path carefully, or else
reporting the tx timestamp will fail. Egress path and ingress path will
finally call sock_recv_timestamp(). We have to distinguish them.
Errqueue is a good indicator to reflect the flow direction.

Suggested-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jason Xing <kernelxing@tencent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20240909015612.3856-2-kerneljasonxing@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jason Xing 2024-09-09 09:56:11 +08:00 committed by Jakub Kicinski
parent e503f82e30
commit be8e9eb375
5 changed files with 35 additions and 5 deletions

View File

@ -267,6 +267,23 @@ SOF_TIMESTAMPING_OPT_TX_SWHW:
two separate messages will be looped to the socket's error queue, two separate messages will be looped to the socket's error queue,
each containing just one timestamp. each containing just one timestamp.
SOF_TIMESTAMPING_OPT_RX_FILTER:
Filter out spurious receive timestamps: report a receive timestamp
only if the matching timestamp generation flag is enabled.
Receive timestamps are generated early in the ingress path, before a
packet's destination socket is known. If any socket enables receive
timestamps, packets for all socket will receive timestamped packets.
Including those that request timestamp reporting with
SOF_TIMESTAMPING_SOFTWARE and/or SOF_TIMESTAMPING_RAW_HARDWARE, but
do not request receive timestamp generation. This can happen when
requesting transmit timestamps only.
Receiving spurious timestamps is generally benign. A process can
ignore the unexpected non-zero value. But it makes behavior subtly
dependent on other sockets. This flag isolates the socket for more
deterministic behavior.
New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to
disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate
regardless of the setting of sysctl net.core.tstamp_allow_data. regardless of the setting of sysctl net.core.tstamp_allow_data.

View File

@ -32,8 +32,9 @@ enum {
SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14), SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
SOF_TIMESTAMPING_BIND_PHC = (1 << 15), SOF_TIMESTAMPING_BIND_PHC = (1 << 15),
SOF_TIMESTAMPING_OPT_ID_TCP = (1 << 16), SOF_TIMESTAMPING_OPT_ID_TCP = (1 << 16),
SOF_TIMESTAMPING_OPT_RX_FILTER = (1 << 17),
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID_TCP, SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_RX_FILTER,
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
SOF_TIMESTAMPING_LAST SOF_TIMESTAMPING_LAST
}; };

View File

@ -427,6 +427,7 @@ const char sof_timestamping_names[][ETH_GSTRING_LEN] = {
[const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw", [const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw",
[const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc", [const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc",
[const_ilog2(SOF_TIMESTAMPING_OPT_ID_TCP)] = "option-id-tcp", [const_ilog2(SOF_TIMESTAMPING_OPT_ID_TCP)] = "option-id-tcp",
[const_ilog2(SOF_TIMESTAMPING_OPT_RX_FILTER)] = "option-rx-filter",
}; };
static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT); static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT);

View File

@ -2235,6 +2235,7 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
struct scm_timestamping_internal *tss) struct scm_timestamping_internal *tss)
{ {
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
u32 tsflags = READ_ONCE(sk->sk_tsflags);
bool has_timestamping = false; bool has_timestamping = false;
if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) { if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) {
@ -2274,14 +2275,18 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
} }
} }
if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_SOFTWARE) if (tsflags & SOF_TIMESTAMPING_SOFTWARE &&
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
has_timestamping = true; has_timestamping = true;
else else
tss->ts[0] = (struct timespec64) {0}; tss->ts[0] = (struct timespec64) {0};
} }
if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) { if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_RAW_HARDWARE) if (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
has_timestamping = true; has_timestamping = true;
else else
tss->ts[2] = (struct timespec64) {0}; tss->ts[2] = (struct timespec64) {0};

View File

@ -946,11 +946,17 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
memset(&tss, 0, sizeof(tss)); memset(&tss, 0, sizeof(tss));
tsflags = READ_ONCE(sk->sk_tsflags); tsflags = READ_ONCE(sk->sk_tsflags);
if ((tsflags & SOF_TIMESTAMPING_SOFTWARE) && if ((tsflags & SOF_TIMESTAMPING_SOFTWARE &&
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
skb_is_err_queue(skb) ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) &&
ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0)) ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0))
empty = 0; empty = 0;
if (shhwtstamps && if (shhwtstamps &&
(tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
skb_is_err_queue(skb) ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) &&
!skb_is_swtx_tstamp(skb, false_tstamp)) { !skb_is_swtx_tstamp(skb, false_tstamp)) {
if_index = 0; if_index = 0;
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV) if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV)