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.
Unified · Split
| @@ -267,6 +267,23 @@ SOF_TIMESTAMPING_OPT_TX_SWHW: · 266 unmodified lines | |||
| 267 | two separate messages will be looped to the socket's error queue, | 267 | two separate messages will be looped to the socket's error queue, |
| 268 | each containing just one timestamp. | 268 | each containing just one timestamp. |
| 269 | 269 | ||
| 270 | SOF_TIMESTAMPING_OPT_RX_FILTER: | ||
| 271 | Filter out spurious receive timestamps: report a receive timestamp | ||
| 272 | only if the matching timestamp generation flag is enabled. | ||
| 273 | |||
| 274 | Receive timestamps are generated early in the ingress path, before a | ||
| 275 | packet's destination socket is known. If any socket enables receive | ||
| 276 | timestamps, packets for all socket will receive timestamped packets. | ||
| 277 | Including those that request timestamp reporting with | ||
| 278 | SOF_TIMESTAMPING_SOFTWARE and/or SOF_TIMESTAMPING_RAW_HARDWARE, but | ||
| 279 | do not request receive timestamp generation. This can happen when | ||
| 280 | requesting transmit timestamps only. | ||
| 281 | |||
| 282 | Receiving spurious timestamps is generally benign. A process can | ||
| 283 | ignore the unexpected non-zero value. But it makes behavior subtly | ||
| 284 | dependent on other sockets. This flag isolates the socket for more | ||
| 285 | deterministic behavior. | ||
| 286 | |||
| 270 | New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to | 287 | New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to |
| 271 | disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate | 288 | disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate |
| 272 | regardless of the setting of sysctl net.core.tstamp_allow_data. | 289 | regardless of the setting of sysctl net.core.tstamp_allow_data. |
| @@ -32,8 +32,9 @@ enum { · 31 unmodified lines | |||
| 32 | SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14), | 32 | SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14), |
| 33 | SOF_TIMESTAMPING_BIND_PHC = (1 << 15), | 33 | SOF_TIMESTAMPING_BIND_PHC = (1 << 15), |
| 34 | SOF_TIMESTAMPING_OPT_ID_TCP = (1 << 16), | 34 | SOF_TIMESTAMPING_OPT_ID_TCP = (1 << 16), |
| 35 | SOF_TIMESTAMPING_OPT_RX_FILTER = (1 << 17), | ||
| 35 | 36 | ||
| 36 | SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID_TCP, | 37 | SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_RX_FILTER, |
| 37 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | | 38 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | |
| 38 | SOF_TIMESTAMPING_LAST | 39 | SOF_TIMESTAMPING_LAST |
| 39 | }; | 40 | }; |
| @@ -427,6 +427,7 @@ const char sof_timestamping_names[][ETH_GSTRING_LEN] = { · 426 unmodified lines | |||
| 427 | [const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw", | 427 | [const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw", |
| 428 | [const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc", | 428 | [const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc", |
| 429 | [const_ilog2(SOF_TIMESTAMPING_OPT_ID_TCP)] = "option-id-tcp", | 429 | [const_ilog2(SOF_TIMESTAMPING_OPT_ID_TCP)] = "option-id-tcp", |
| 430 | [const_ilog2(SOF_TIMESTAMPING_OPT_RX_FILTER)] = "option-rx-filter", | ||
| 430 | }; | 431 | }; |
| 431 | static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT); | 432 | static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT); |
| 432 | 433 | ||
| @@ -2235,6 +2235,7 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk, · 2234 unmodified lines | |||
| 2235 | struct scm_timestamping_internal *tss) | 2235 | struct scm_timestamping_internal *tss) |
| 2236 | { | 2236 | { |
| 2237 | int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); | 2237 | int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); |
| 2238 | u32 tsflags = READ_ONCE(sk->sk_tsflags); | ||
| 2238 | bool has_timestamping = false; | 2239 | bool has_timestamping = false; |
| 2239 | 2240 | ||
| 2240 | if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) { | 2241 | 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, · 33 unmodified lines | |||
| 2274 | } | 2275 | } |
| 2275 | } | 2276 | } |
| 2276 | 2277 | ||
| 2277 | if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_SOFTWARE) | 2278 | if (tsflags & SOF_TIMESTAMPING_SOFTWARE && |
| 2279 | (tsflags & SOF_TIMESTAMPING_RX_SOFTWARE || | ||
| 2280 | !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) | ||
| 2278 | has_timestamping = true; | 2281 | has_timestamping = true; |
| 2279 | else | 2282 | else |
| 2280 | tss->ts[0] = (struct timespec64) {0}; | 2283 | tss->ts[0] = (struct timespec64) {0}; |
| 2281 | } | 2284 | } |
| 2282 | 2285 | ||
| 2283 | if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) { | 2286 | if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) { |
| 2284 | if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_RAW_HARDWARE) | 2287 | if (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE && |
| 2288 | (tsflags & SOF_TIMESTAMPING_RX_HARDWARE || | ||
| 2289 | !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) | ||
| 2285 | has_timestamping = true; | 2290 | has_timestamping = true; |
| 2286 | else | 2291 | else |
| 2287 | tss->ts[2] = (struct timespec64) {0}; | 2292 | tss->ts[2] = (struct timespec64) {0}; |
| @@ -946,11 +946,17 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, · 945 unmodified lines | |||
| 946 | 946 | ||
| 947 | memset(&tss, 0, sizeof(tss)); | 947 | memset(&tss, 0, sizeof(tss)); |
| 948 | tsflags = READ_ONCE(sk->sk_tsflags); | 948 | tsflags = READ_ONCE(sk->sk_tsflags); |
| 949 | if ((tsflags & SOF_TIMESTAMPING_SOFTWARE) && | 949 | if ((tsflags & SOF_TIMESTAMPING_SOFTWARE && |
| 950 | (tsflags & SOF_TIMESTAMPING_RX_SOFTWARE || | ||
| 951 | skb_is_err_queue(skb) || | ||
| 952 | !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) && | ||
| 950 | ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0)) | 953 | ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0)) |
| 951 | empty = 0; | 954 | empty = 0; |
| 952 | if (shhwtstamps && | 955 | if (shhwtstamps && |
| 953 | (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && | 956 | (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE && |
| 957 | (tsflags & SOF_TIMESTAMPING_RX_HARDWARE || | ||
| 958 | skb_is_err_queue(skb) || | ||
| 959 | !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) && | ||
| 954 | !skb_is_swtx_tstamp(skb, false_tstamp)) { | 960 | !skb_is_swtx_tstamp(skb, false_tstamp)) { |
| 955 | if_index = 0; | 961 | if_index = 0; |
| 956 | if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV) | 962 | if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV) |