Interleave sending and receiving of packets to reduce rx latency#515
Interleave sending and receiving of packets to reduce rx latency#515kaczmarczyck merged 26 commits intogoogle:developfrom
Conversation
src/ctap/mod.rs
Outdated
| debug_ctap!(env, "Sent KEEPALIVE packet"); | ||
| } | ||
| Ok(SendOrRecvStatus::Received) => { | ||
| Ok(SendOrRecvStatus::Received(_)) => { |
There was a problem hiding this comment.
What if we receive on a different endpoint than the one being kept alive? Does it mean we discard it?
There was a problem hiding this comment.
Good find.
At present we discard it. I've added a TODO to address this (for a later PR), but I can address it here is you'd prefer.
There was a problem hiding this comment.
I guess it's not really a regression (but I might be wrong). So I would say it's ok to do it later.
There was a problem hiding this comment.
I think it is a regression if we receive, but the channel ID is by chance the same. Then a different transport would interact with this channel.
There was a problem hiding this comment.
Yes, good point.
I can add a check for this.
However, I am wondering about a bigger change. If the code ignores packets on the other interface, then those packets are lost. So perhaps the better approach is to send() but not send_and_recv() at this time. That way the incoming packets are not serviced and will sit there. Looking at the code, it looks challenging to connect incoming packets to the other interface without massive refactoring.
Thoughts?
There was a problem hiding this comment.
I generally agree that a send / receive interface would be cleaner. The current solution is there for practical reasons. USB Request Blocks (URB) that need to be answered quickly. And if you only send and have the syscall roundtrip delay from that, you can't answer OUT packets in time.
If you try to go for a send / receive interface, please test for everything that didn't work last time.
@gendx @jmichelp are the original authors who made that decision. Maybe they can help describe a few test cases to look out for?
There was a problem hiding this comment.
OK.
What I've done in the short term is ignore those packet on the other interface. This stops the regression and leaves room for the above discussed improvements at a later date.
I've add tests to ./tools/vendor_hid_tests.py to verify this behavior.
ia0
left a comment
There was a problem hiding this comment.
Looks good on my side. I'll be OOO until Aug 3rd so don't wait for me if there are me updates.
src/ctap/mod.rs
Outdated
| debug_ctap!(env, "Sent KEEPALIVE packet"); | ||
| } | ||
| Ok(SendOrRecvStatus::Received) => { | ||
| Ok(SendOrRecvStatus::Received(_)) => { |
There was a problem hiding this comment.
I think it is a regression if we receive, but the channel ID is by chance the same. Then a different transport would interact with this channel.
kaczmarczyck
left a comment
There was a problem hiding this comment.
2 high level comments:
-
The new main is different enough (i.e. might discard replies) that we should test OpenSK a bit with it.
-
The test script entangles raw HID and libfido. I don't think there is an elegant solution for this, but I thought it's interesting to mention that there is a way to make libfido talk to the second usage page. You monkey patch it's usage page:
import fido2
fido2.hid.base.FIDO_USAGE_PAGE = 0xFF00
You have to be careful to do that after GetInfo though, or we patch OpenSK to allow GetInfo on the second usage page. Not saying this approach is better or you should do it, it's just a different tradeoff I think.
Testing with https://github.com/google/CTAP2-test-tool shows no differences.
Good approach. I've used this idea. |
As discussed in #502 and #514 packet processing latency is too slow when both interfaces are being used. Another cause for this is that when a reply is being sent, it does so in a tight loop (ie inner loop in the main function) without receiving any other packets. This can easily introduce hundreds of milliseconds delay.
This PR removes the innner loop in main and leaves just a single loop. Each iteration it will optionally send a packet and always attempt to receive an incoming packet (#514 ensures suitable routing of the oldest packet). For our use case, the processing of these packets will be interleaved across the FIDO and Vendor HID interfaces (if both are present).
Several changes are required for this: