Skip to content
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

Full picture of in memory listener and connection #13361

Closed
wants to merge 45 commits into from

Conversation

lambdai
Copy link
Contributor

@lambdai lambdai commented Oct 1, 2020

A almost rewrite of #12537

Prototype of #11725

Implementations

  • buffered_io_socket_handle_impl
    Replaced the BufferSource transport socket. So existing transport socket could be supported. Special thank to @florincoras 's work dropping the file descriptor in transport sockets and other filters!
    This is an socket handle which owns a buffer. Think the buffer as the socket buffer in the kernel. This handle should be always created with a peer so that this handle could write to peer's buffer, and notify readable or writable signal along with read/write/shutdown.
  • new api in dispatcher
    Allow register internal listener and target listener when a client connection need to be created
  • new internal listener impl along with connection_handler
    Register internal listener by name and "accept" connection. Currently internal listener could simulate tcp listener but not udp listener.

Past work

lambdai added 30 commits August 27, 2020 05:17
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #13361 was opened by lambdai.

see: more, trace.

@lambdai
Copy link
Contributor Author

lambdai commented Oct 1, 2020

@alyssawilk Please ignore the verbose log. I will clean up the log along with individual PRs

Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @lambdai, it's really exciting to see progress on this one!

I think the overall structure is fine. My WIP pass comments are to see where we can reduce duplicated code - the auto-close connection I think can be cleaned up and I'm wondering if we can also do some around the ActiveInternal classes.
To get this landed I also think we're going to need to split this up, rather than have one giant PR. I wonder if we can land the BufferedIoSocketHandleImpl with utilitiy classes but minimal changes to core code. WDYT?

* Creates an client internal connection. Does NOT initiate the connection;
* the caller must then call connect() on the returned Network::ClientConnection.
* @param internal_address supplies the internal address to connect to.
* @param local_address supplies an address to bind to or nullptr if no bind is necessary.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain what binding is in internal address context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Will add that listener side connection could obtain the bind local address for debug.

I also want to add here that I want to introduce a generic "socket options" param in the future to deliver more information including "original address" which is supposed to be "ip/port" address raising this internal address.

namespace {
Network::Address::InstanceConstSharedPtr
nextClientAddress(const Network::Address::InstanceConstSharedPtr& server_address) {
uint64_t id = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you mean this to be static? If so fix and test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. It should be static. The local address is well used, only need to guarantee such address is not nullptr.
Look like you are fine with such a debug purpose address :)

for (const auto& [name, _] : internal_listeners_) {
ENVOY_LOG_MISC(debug, "lambdai: p listener {}", name);
}
if (iter == internal_listeners_.end()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, I would have expected this in connect(). When we do normal IP style create and connect do we validate before connect?
no strong opinion either way, but if you prefer this maybe comment about where validation is done in include/ ?

Actually I think if you move this work to CONNECT you can skip the entire closingClientConnectionImpl which would be nice clean up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I want to split ClosingClientConnectionImpl and ClientConnectionImpl:

The underlying BufferedIoSocketHandleImpl is aware of single transition: from "connected" to "disconnected".
If we set up the server connection in connect(), the client connection need to track "uninitialized" to "connected", "uninitialized" to "fail to connect".

BTW, The model internal connection I am borrowing from "socketpair()"

// Find the internal listener callback. The listener will setup the server connection.
auto iter = internal_listeners_.find(internal_address->asString());
for (const auto& [name, _] : internal_listeners_) {
ENVOY_LOG_MISC(debug, "lambdai: p listener {}", name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm inclined to do my next pass once you've had a chance to clean these up, and do a sweep to make sure the code is commented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is adding 3000 lines. Do you think it is realistic to merge this PR without splitting?

If not I prefer to keep the debug purpose log: I will backport the split PRs and see if the sub PRs breaks this overall PR: This PR has quite a few real world integration tests. These integration tests must pass but cannot be put in early sub PRs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think given the complexity it'd be better to split out what we can. It could be that it's just 2-3? As said I think the buffer code would split out pretty easily so let's give that a try and see what's left.
Also w.r.t. logging I think it's fine to leave many of the logs in (all the error corner case logs for example) and just move them from lambdai/LOG_MISC to real logs. It's fine to tackle that as the last step when the big PR is ready for review if you prefer.

if (iter == internal_listeners_.end()) {
ENVOY_LOG_MISC(debug, "lambdai: no valid listener registered for envoy internal address {}",
internal_address->asString());
return std::make_unique<Network::ClosingClientConnectionImpl>(*this, internal_address,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also some of these are good to keep as debug logs, though not MISC_LOG

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. Will assign reasonable logger and level in the split PRs

Copy link
Contributor Author

@lambdai lambdai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review! Let me add comments first

* Creates an client internal connection. Does NOT initiate the connection;
* the caller must then call connect() on the returned Network::ClientConnection.
* @param internal_address supplies the internal address to connect to.
* @param local_address supplies an address to bind to or nullptr if no bind is necessary.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Will add that listener side connection could obtain the bind local address for debug.

I also want to add here that I want to introduce a generic "socket options" param in the future to deliver more information including "original address" which is supposed to be "ip/port" address raising this internal address.

namespace {
Network::Address::InstanceConstSharedPtr
nextClientAddress(const Network::Address::InstanceConstSharedPtr& server_address) {
uint64_t id = 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. It should be static. The local address is well used, only need to guarantee such address is not nullptr.
Look like you are fine with such a debug purpose address :)

// Find the internal listener callback. The listener will setup the server connection.
auto iter = internal_listeners_.find(internal_address->asString());
for (const auto& [name, _] : internal_listeners_) {
ENVOY_LOG_MISC(debug, "lambdai: p listener {}", name);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is adding 3000 lines. Do you think it is realistic to merge this PR without splitting?

If not I prefer to keep the debug purpose log: I will backport the split PRs and see if the sub PRs breaks this overall PR: This PR has quite a few real world integration tests. These integration tests must pass but cannot be put in early sub PRs.

for (const auto& [name, _] : internal_listeners_) {
ENVOY_LOG_MISC(debug, "lambdai: p listener {}", name);
}
if (iter == internal_listeners_.end()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I want to split ClosingClientConnectionImpl and ClientConnectionImpl:

The underlying BufferedIoSocketHandleImpl is aware of single transition: from "connected" to "disconnected".
If we set up the server connection in connect(), the client connection need to track "uninitialized" to "connected", "uninitialized" to "fail to connect".

BTW, The model internal connection I am borrowing from "socketpair()"

if (iter == internal_listeners_.end()) {
ENVOY_LOG_MISC(debug, "lambdai: no valid listener registered for envoy internal address {}",
internal_address->asString());
return std::make_unique<Network::ClosingClientConnectionImpl>(*this, internal_address,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. Will assign reasonable logger and level in the split PRs

Comment on lines +154 to +155
auto client_io_handle_ = std::make_unique<Network::BufferedIoSocketHandleImpl>();
auto server_io_handle_ = std::make_unique<Network::BufferedIoSocketHandleImpl>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BufferedIoSocketHandleImpl as extension here?

@github-actions
Copy link

github-actions bot commented Dec 9, 2020

This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@github-actions github-actions bot added the stale stalebot believes this issue/PR has not been touched recently label Dec 9, 2020
@github-actions
Copy link

This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@github-actions github-actions bot closed this Dec 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api stale stalebot believes this issue/PR has not been touched recently
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants