api: add envoy internal address#12837
Conversation
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]>
|
Chatted offline: I want to clarify that
These connection attributes will be gradually added in the further PRs so that virtual address could support various of network filters, listener filters |
alyssawilk
left a comment
There was a problem hiding this comment.
Looks good - just a few minor nits on my end.
source/common/network/address_impl.h
Outdated
| const Ip* ip() const override { return nullptr; } | ||
| const Pipe* pipe() const override { return nullptr; } | ||
| const EnvoyInternalAddress* envoyInternalAddress() const override { return &internal_address_; } | ||
| const sockaddr* sockAddr() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } |
There was a problem hiding this comment.
I'm mildly concerned that a panic() isn't the right call here. Can you take a peek at call sites and see what we should do here to make sure these can never be called for the new address type?
We should probably also update the comments in the include directory to make it clear when it's safe to call and when it's not.
There was a problem hiding this comment.
With NOT_IMPLEMENTED_GCOVR_EXCL_LINE it means
If the later version of control plane send the config containing EnvoyInternalAddress,
this particular version with this PR but no further of envoy might crash.
There was a problem hiding this comment.
What I can do is to find the potential usage of
this new type of address.
Listener and Endpoint as a immediate candidate, making sure these are either
invalidate config per config update, mostly in master thread.
or fail the connection when this address is used.
What else can I do?
There was a problem hiding this comment.
I think if we are making implementation of parts of the interface optional (panic if called), we either need to have TODOs to implement later or TODOs to check all call sites to make them internal-address compatible. Having bits of an interface which may work for some address and may not work for others, and no checks in the code base makes me uncomfortable. Again cc @mattklein123 in case he has other ideas of how to aim the decaped TCP stream back into a new envoy filter chain without a half-working address class.
There was a problem hiding this comment.
Updated to return nullptr and I mentally go through all the sockAddr() usage in the existing code base: all of them accepts nullptr usage without crash.
Luckily these usages are inline followed by syscall (connect/bind/send/recv) so I could inject syscall error code as if the following syscalls fail.
Now I believe these errors are now non-fatal.
alyssawilk
left a comment
There was a problem hiding this comment.
Also can you make sure to fill out the rest of the template for your PRs?
for this one I'd say something like
Risk Level: low (code unused)
Testing: new unit tests
Docs Changes: n/a
Release Notes: n/a
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
|
For internal address as server address: I add the validation that all listener should reference internal address. Internal address as client address is much harder. I am more than happy to hear the alternative approaches from you @alyssawilk Thank you in advance! |
alyssawilk
left a comment
There was a problem hiding this comment.
Please check CI, it looks like it is not passing.
source/common/network/address_impl.h
Outdated
| const Ip* ip() const override { return nullptr; } | ||
| const Pipe* pipe() const override { return nullptr; } | ||
| const EnvoyInternalAddress* envoyInternalAddress() const override { return &internal_address_; } | ||
| const sockaddr* sockAddr() const override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } |
There was a problem hiding this comment.
I think if we are making implementation of parts of the interface optional (panic if called), we either need to have TODOs to implement later or TODOs to check all call sites to make them internal-address compatible. Having bits of an interface which may work for some address and may not work for others, and no checks in the code base makes me uncomfortable. Again cc @mattklein123 in case he has other ideas of how to aim the decaped TCP stream back into a new envoy filter chain without a half-working address class.
| const Address::InstanceConstSharedPtr addr) { | ||
| // Cannot create IoHandle for internal address yet. | ||
| if (addr->envoyInternalAddress()) { | ||
| return nullptr; |
There was a problem hiding this comment.
if this stands, there should be a unit test please.
There was a problem hiding this comment.
You are so right! My brain stop working last night so I pushed before I save this change.
The latest update has an integration test connecting to a internal address
| static inline IoHandlePtr ioHandleForAddr(Socket::Type type, | ||
| const Address::InstanceConstSharedPtr addr) { | ||
| // Cannot create IoHandle for internal address yet. | ||
| if (addr->envoyInternalAddress()) { |
There was a problem hiding this comment.
Unfortunately this looks like it's solid error handling but most callers of ioHandleForAddr will crash if it returns nullptr.
@mattklein123 @lambdai 's plan is basically creating this new listener type to be able to point a "cluster" at this new virtual address. Any thoughts on how that might best be done without causing this cascading chain of not-fully-implemented things?
There was a problem hiding this comment.
I fixed this by providing the NullIoSocketHandleImpl to give it a socket handle allow upper layer to create a connection but will fail to send/recv.
https://github.com/envoyproxy/envoy/pull/12837/files#r483259684
There was a problem hiding this comment.
The ideal case is control plane never send unsupported addresses before envoy could support.
- Mark the cluster config invalid if it contains internal address. It's always safer to reject cluster configs at master.
I did this check in LDS config as well. That is easy since LDS is the only entrance to receive new listener config. - In case of escaped internal address which we fail to invalid, the NullIoSocketHandle could fail the per client connect.
This NullSocketHandle could also support mingled addresses such as
endpoints:
- internal address: "not_yet_supported_listener_address"
- socket address: "127.0.0.1:80"
Signed-off-by: Yuchen Dai <[email protected]>
| /** | ||
| * IoHandle for invalid socket. This is rquired because Envoy expects IoHandle creation never fail. | ||
| * This NullIoSocketHandleImpl allows Envoy surives on unsupported socket options. | ||
| */ | ||
| class NullIoSocketHandleImpl : public IoHandle, protected Logger::Loggable<Logger::Id::io> { | ||
| public: | ||
| NullIoSocketHandleImpl() : closed_{false} { |
| // Test that connecting to internal address should always followed by disconnection with no crash. | ||
| TEST_P(SocketInterfaceIntegrationTest, InternalAddressWithSocketInterface) { | ||
| BaseIntegrationTest::initialize(); | ||
|
|
||
| ConnectionStatusCallbacks connect_callbacks_; | ||
| Network::ClientConnectionPtr client_; | ||
| const Network::SocketInterface* sock_interface = Network::socketInterface( | ||
| "envoy.extensions.network.socket_interface.default_socket_interface"); | ||
| Network::Address::InstanceConstSharedPtr address = | ||
| std::make_shared<Network::Address::EnvoyInternalInstance>("listener_0", sock_interface); | ||
|
|
||
| client_ = dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), | ||
| Network::Test::createRawBufferSocket(), nullptr); | ||
|
|
||
| client_->addConnectionCallbacks(connect_callbacks_); | ||
| client_->connect(); | ||
|
|
||
| while (!connect_callbacks_.closed()) { | ||
| dispatcher_->run(Event::Dispatcher::RunType::NonBlock); | ||
| } | ||
|
|
||
| client_->close(Network::ConnectionCloseType::FlushWrite); | ||
| } |
There was a problem hiding this comment.
Testing Dispatcher::createClientConnection(). This should cover the client tcp connection IMO.
I have the concern of unknown unknown...
Now I am adding UDP socket test
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]>
|
clang tidy is still failing. Let me know when this is ready for another pass? |
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
|
The recent update is that socket manipulation on internal address are non-fatal. The goal is to enable internal address usage everywhere. Let me know if this is good enough to move on. Thanks! |
alyssawilk
left a comment
There was a problem hiding this comment.
OK, as discussed on slack let's hide the config and remove some of the temporary classes with TODOs (it's Ok to crash if you're configuring Envoy with hidden incomplete-implementation code :-P )
Thanks so much for bearing with me on this!
|
Yes, fine to leave docs until we un-hide. |
|
/lgtm api |
lambdai
left a comment
There was a problem hiding this comment.
Thanks! Updating PR
Signed-off-by: Yuchen Dai <[email protected]>
|
I find a machine running sphinx correct and fixed the docs. It turns out to be EnvoyInternalAddress field(located in one_of) must be marked hidden as well. Now the doc should pass on CI... |
@htuch Sorry... another api approval is needed b/c my doc fix :( |
alyssawilk
left a comment
There was a problem hiding this comment.
LGTM! over to @mattklein123
mattklein123
left a comment
There was a problem hiding this comment.
LGTM at a high level, though, I wonder whether it's really worth landing this PR vs. the real implementation. Some small comments. Thank you!
/wait
| ENVOY_LOG(debug, | ||
| "listener {} has envoy internal address {}. Internal address cannot be used by " | ||
| "listener yet", | ||
| config.name(), config.address().envoy_internal_address().DebugString()); | ||
| return false; |
There was a problem hiding this comment.
Just use NOT_IMPLEMENTED? Or just ASSERT not has_envoy_internal_address? Seems not worth it to handle this case right now.
There was a problem hiding this comment.
NOT_IMPLEMENTED will crash the Envoy. That is not expected.
ASSERT could replace the the ENVOY_LOG, but this if branch should be kept in case Envoy does receive a listener config with internal address. Schema check is not helping here.
There was a problem hiding this comment.
What is the point of this PR? It's not that many lines of code and it doesn't actually do anything? I would rather you either a) just hold this PR and implement the full thing or b) put in ASSERT or RELEASE_ASSERT for stuff like this since you have a not implemented and not documented feature. It doesn't make any sense to add this type of logic.
There was a problem hiding this comment.
I'd like to push api first as the conversion.
I don't get your plan b RELEASE_ASSERT is easier but it will crash Envoy. Why do you prefer an unsupported listener config crashing Envoy? With these lines above envoy would NACK the listener config without crash.
There was a problem hiding this comment.
Because you are adding error handling/logging logic for something that is not implemented. It bloats the code base for no good reason. If you want to make sure it crashes, do RELEASE_ASSERT(..., "this is not implemented yet."). Thanks.
/wait
There was a problem hiding this comment.
Oh, to NACK I should throw exception instead of return false.
There was a problem hiding this comment.
@mattklein123 Is throwing EnvoyException beating return false and RELEASE_ASSERT?
There was a problem hiding this comment.
No. Crash, or please just close this PR and reopen when there is an implementation. It does not make any sense to add actual error handling for an unimplemented partial feature.
There was a problem hiding this comment.
Happy to crash and move to next listener config api.
And then the internal connection driven by scheduler.
Running tests...
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
|
/lgtm api |
Signed-off-by: Yuchen Dai <[email protected]>
Signed-off-by: Yuchen Dai <[email protected]>
|
Thank you @mattklein123 |
Commit Message:
Add envoy internal address for envoy internal connection.
Signed-off-by: Yuchen Dai [email protected]
Additional Description:
Part of #11725
Risk Level: low (code unused)
Testing: new unit tests
Docs Changes: n/a
Release Notes: n/a