-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
event: assert the case of both read and closed event registered #18265
Conversation
Waiting for the comment from @davinci26 at #17395 (comment) cc @davinci26 @wrowe |
/retest |
Retrying Azure Pipelines: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this looks reasonable to me. There are still some tests that are not passing on windows, I can help with debugging those tomorrow.
Adding also @antoniovicente to take a look as he is really well versed on the subject.
(edit: I have a PR to fix coverage flakes so you might want to pick up main when #18571 is merged)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable. I would recommend looping in code owners for the HTTP and TLS inspectors.
@@ -28,6 +28,9 @@ FileEventImpl::FileEventImpl(DispatcherImpl& dispatcher, os_fd_t fd, FileReadyCb | |||
"Cannot use EmulatedEdge events if they are not the default platform type"); | |||
} | |||
|
|||
// We never ask for both early close and read at the same time. | |||
ASSERT(!(events & FileReadyType::Read && (events & FileReadyType::Closed))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're not asserting this condition in FileEventImpl::updateEvents
Can I suggest you move this assert to assignEvents so both cases are covered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, that is better, let me try
new_event_mask = new_event_mask & ~FileReadyType::Read; | ||
} | ||
// We never ask for both early close and read at the same time. | ||
ASSERT(!(event & FileReadyType::Read && (enabled_events_ & FileReadyType::Closed))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to ASSERT against new_event_mask instead.
// inspector is always peeking and can never determine EOF. | ||
// Use this event type to avoid listener timeout on the OS supporting | ||
// FileReadyType::Closed. | ||
bool end_stream = events & Event::FileReadyType::Closed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments imply that including Closed in the event mask is important. IIRC Closed events are not supported on Mac, so relying on Closed events seems broken. At some point in the future I may try to reduce our reliance on them but that is unlikely to happen anytime soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean reduce the reliance on Closed
event? I may can help after finishing the current task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, stop using Closed events in the envoy implementation. It's not an easy task as it interacts in intrusive ways with the way Connection readDisable is implemented.
Yea, I guess they are @ggreenway and @alyssawilk :) |
thanks! I will give it a try today, hope my windows dev env works. |
@davinci26 I probably need your help, I don't know why there is no |
I think this is a difference in to libevent, because at the end no events are registered on windows (all of them are unregistered) libevent closes the event loop and thus the watcher event is not emitted. I think we should guard the failing expectation based on the underlying event type |
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu <[email protected]>
3aab6ac
to
481a41c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me
Signed-off-by: He Jie Xu <[email protected]>
/retest |
@antoniovicente are you able to finish off the review of this one? Or is there someone else that can take that over? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davinci26 could review and approve this change? It relates to Windows emulated edge behavior.
@@ -120,7 +123,6 @@ void FileEventImpl::unregisterEventIfEmulatedEdge(uint32_t event) { | |||
ASSERT(dispatcher_.isThreadSafe()); | |||
// This constexpr if allows the compiler to optimize away the function on POSIX | |||
if constexpr (PlatformDefaultTriggerType == FileTriggerType::EmulatedEdge) { | |||
ASSERT((event & (FileReadyType::Read | FileReadyType::Write)) == event); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you shed some light as to why this ASSERT was removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we assert the same at assignEvents
, it will be invoked by updateEvents
at line 128 also. So I remove this since it is duplicated
if (event & FileReadyType::Read && (enabled_events_ & FileReadyType::Closed)) { | ||
// We never ask for both early close and read at the same time. | ||
new_event_mask = new_event_mask & ~FileReadyType::Read; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem safe to me to remove this code. This is a change in behavior in cases where the ASSERT above about not allowing read and closed at the same time fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it, let me add it back.
if (events & FileReadyType::Closed && injected_activation_events_ & FileReadyType::Read) { | ||
// We never ask for both early close and read at the same time. If close is requested | ||
// keep that instead. | ||
injected_activation_events_ = injected_activation_events_ & ~FileReadyType::Read; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above, this is a change in behavior. Adding an ASSERT is not a guarantee that these cases won't come up while running a real proxy.
Also note that injected_activation_events_ may contain events that the connection is not registered for. I don't think it happens often but it is technically allowed.
// We never ask for both early close and read at the same time. | ||
new_event_mask = new_event_mask & ~FileReadyType::Read; | ||
} | ||
// We never ask for both early close and read at the same time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davinci26 Can you confirm that libevent on Windows supports EV_CLOSE?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does EV_CLOSE correspond to EPOLLRDHUP
? if yes then it is supported on wepoll
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like it. I guess Windows and Linux support this, but not Mac which uses the kqueue for event handling in libevent.
Signed-off-by: He Jie Xu <[email protected]>
@davinci26 any further comments? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
* main: (221 commits) deps: Bump `protobuf` -> 3.19.0 (envoyproxy#18471) tooling: auto-assign dependency shephards (envoyproxy#18794) clang-tidy: Return from diff fun if empty diff (envoyproxy#18815) repokitteh: Block PRs pending deps approval (envoyproxy#18814) deps: Bump `org_llvm_llvm` -> 12.0.1, `com_github_wavm_wavm` -> 9ffd3e2 (envoyproxy#18747) dns resolvers: add All lookup mode (envoyproxy#18464) doc: fix link formatting for TLS session_timeout (envoyproxy#18790) ext_authz: Set response flag and code details to UAEX when denied (envoyproxy#18740) socket options: add support for directly creating ipv4/ipv6 pairs (envoyproxy#18769) ecds: make onConfigUpdate generic over filter type (envoyproxy#18061) bazel: update CMake instructions in EXTERNAL_DEPS.md (envoyproxy#18799) upstream: fix typo in comment (envoyproxy#18798) runtime: removing envoy.reloadable_features.grpc_json_transcoder_adhere_to_buffer_limits (envoyproxy#18696) bazel: Add CC=clang to clang configuration (envoyproxy#18732) fix error request id in the dubbbo local reply (envoyproxy#18741) event: assert the case of both read and closed event registered (envoyproxy#18265) tcp proxy connect tunneling: improved testing (envoyproxy#18784) deps: Bump `protoc-gen-validate` -> 0.6.2 (envoyproxy#18742) deps: Bump `rules_pkg` -> ad57589 (envoyproxy#18746) bazel: copy .bazelversion for envoy filter examples (envoyproxy#18730) ... Signed-off-by: Michael Puncel <[email protected]>
@soulxu I just found an obscure corner-case bug introduced by this change. For the listener filters that MSG_PEEK (http_inspector, tls_inspector), if the client sends some data with a FIN, the filter can't detect that the connection is closed. It has logic to check the return value for zero, but this won't happen since the data is never removed from the socket due to the MSG_PEEK. However, I don't know that it matters much; the |
I will do some tests. It sounds like we will have different behavior between linux and windows. Maybe it should be ok for windows after we have emulated MSG_PEEK. But let me do some tests and think about it. |
I wrote a test https://github.com/envoyproxy/envoy/pull/19883/files, the test won't execute successful, but I can get the log. it seems the recv with MSG_PEEK will return 0 when the connection closed. But let me know if didn't test it with right way.
I also lookup the discussion history, davinci26 mentioned that the remote close will trigger event #17395 (comment) also found this case was spotted out in the review https://github.com/envoyproxy/envoy/pull/18265/files#r726677895 But from the test seems davinci26 was right. |
The proxy protocol listener filter doesn't PEEK, it consumes the data, so it won't hit this case. Try a similar test with http_inspector or tls_inspector. |
oops, right, thanks. let me test again. |
@ggreenway I test those out. The MSG_PEEK won't return 0 when remote closed. It only triggered an event, but the MSG_PEEK still returns the data in the buffer. Seems there is no way to figure out it is a connection close or not. The background is the For the current code, all test works fine with both For removing data peek #17395, #17395 (comment) reference to So thinking about the solution here.
|
Try to understand why we remove Both below two parts handle the case of a read event injected, and closed event was registered. This is for the case read event was injected, and a closed event happened on the real socket. envoy/source/common/event/file_event_impl.cc Lines 154 to 160 in a7af844
This is for the case a read event injected, then ensure we won't register the read event back after consume data. envoy/source/common/event/file_event_impl.cc Lines 138 to 143 in a7af844
So can I understand it like, those change are only for ConnectionImpl to avoid process both read and close event? But for listener filter, we are ok for both read and close event happened (we should be ok for drop the data when close happened). If those understand right, then we can just not removing the read event for listener filter. |
cc @rectified95 who is the working on Msft/Windows |
@davinci26 thanks :) |
@soulxu if this change fixes a case that is supposed to work on windows and previously didn't, and we accidentally broke a case that should never happen and is supposed to fail and now fails a bit slower, I'd say we can leave it; overall behavior is improved. |
I would like to explore this again after |
Previously the PR #18265 removed the `Closed` event for listener filter, since the Windows doesn't work well. There is still have a corner case that can't be handled without the `Closed` event #18265 (comment) This PR tries to introduce the `Closed` event back to the listener filter. As the comments on Windows code said, both `Read` and `Closed` can't be registered at same time due to the `Connection` doesn't support that yet. That means it shouldn't be a problem for the listener filter. Also currently, there is no Envoy code using both `Read` and `Closed` event, so it should be ok to remove those workaround code to make the both `Read` and `Closed` events registered to work with listener filter. The full analysis is here #18265 (comment) Signed-off-by: He Jie Xu <[email protected]>
Previously the PR envoyproxy/envoy#18265 removed the `Closed` event for listener filter, since the Windows doesn't work well. There is still have a corner case that can't be handled without the `Closed` event envoyproxy/envoy#18265 (comment) This PR tries to introduce the `Closed` event back to the listener filter. As the comments on Windows code said, both `Read` and `Closed` can't be registered at same time due to the `Connection` doesn't support that yet. That means it shouldn't be a problem for the listener filter. Also currently, there is no Envoy code using both `Read` and `Closed` event, so it should be ok to remove those workaround code to make the both `Read` and `Closed` events registered to work with listener filter. The full analysis is here envoyproxy/envoy#18265 (comment) Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: He Jie Xu [email protected]
Commit Message: event: assert the case of both read and closed event registered
Additional Description:
On Windows, the Read event may be removed when both the read and closed event are registered. That will lead the thread is waiting for next read event forever. So change to assertion to prevent someone registered both read and closed events.
Risk Level: low
Testing: n/a
Docs Changes: n/a
Release Notes: n/a