-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
network: socket interface support for addresses #12189
Conversation
Signed-off-by: Florin Coras <fcoras@cisco.com>
cc @yanavlasov @htuch Is this in combination with the support for configurable |
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.
Looks right to me, will defer to Yan for review. Thanks.
source/common/network/address_impl.h
Outdated
@@ -54,23 +60,23 @@ class Ipv4Instance : public InstanceBase { | |||
/** | |||
* Construct from an existing unix IPv4 socket address (IP v4 address and port). | |||
*/ | |||
explicit Ipv4Instance(const sockaddr_in* address); | |||
explicit Ipv4Instance(const sockaddr_in* address, const std::string& sock_interface = ""); |
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.
Nit: absl::string_view
for all const std::string&
s.
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.
Done!
source/common/network/socket_impl.cc
Outdated
if (sock_interface != nullptr) { | ||
return sock_interface->socket(type, addr); | ||
} | ||
return nullptr; |
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.
This will cause a SIGSEGV sometime later, right? Maybe the right thing to do is to RELEASE_ASSERT here that the factory for creating IO handles is missing.
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.
Fair point! Made it a RELEASE_ASSERT.
Also would you be able to make unit test exercising this, please? |
Signed-off-by: Florin Coras <fcoras@cisco.com>
- absl::string_view instead of const std::string& - RELEASE_ASSERT if address socket_interface not found - added integration test for address with socket_interface set Signed-off-by: Florin Coras <fcoras@cisco.com>
Done! Added an integration test which opens a connection with an address that explicitly asks for the default socket interface |
@yanavlasov, I suspect the arm failure is just a flake. After you get a chance to review the PR, I'll merge master and hopefully it'll go away. |
@florincoras thanks it looks good. Would it be possible to also have a test that tests complete plumbing with a custom |
I suspect my description above was misleading. The default In short, to implement a new, configurable Also, this static global init is why we don't always need to configure a default interface in the startup config file.
Cool idea! :-D |
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 with small comment, thanks. Please also merge main as there have been many CI fixes.
/wait
const Address::InstanceConstSharedPtr addr) { | ||
auto sock_interface_name = addr->socketInterface(); | ||
if (!sock_interface_name.empty()) { | ||
auto sock_interface = const_cast<SocketInterface*>(socketInterface(sock_interface_name)); |
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.
nit: this const_cast seems a bit off. Any reason to not just fix the socket method itself to be const?
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.
I thought about that too but socket()
could end up changing the SocketInterface
object. The alternative would be to remove const from SocketInterface
and trust that callers won't do anything irresponsible.
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.
Why would it change the interface object? Does that happen in practice right now? Can we cross that bridge later if we come to it? If it really is a mutable thing I would just remove const.
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.
I was thinking that interface objects could be tracking the sockets, e.g., they could be building some form of socket descriptor map. We're not doing that now, as we're offloading everything to the kernel, but I did hit this particular issue with a custom socket interface implementation. But okay, let's cross that bridge later :-)
- make socket apis const for now Signed-off-by: Florin Coras <fcoras@cisco.com>
Signed-off-by: Florin Coras <fcoras@cisco.com>
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.
Thanks!
auto sock_interface_name = addr->socketInterface(); | ||
if (!sock_interface_name.empty()) { | ||
auto sock_interface = socketInterface(sock_interface_name); | ||
RELEASE_ASSERT(sock_interface != nullptr, |
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.
Regarding this RELEASE_ASSERT, what guarantees that the interface names returned by the address are valid?
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.
By default, the names are null. If anybody sets a name on the address, e.g., resolvers, the expectation is that those names are valid. The alternative would be to silently accept errors and use the default SocketInterface
implementation but that would just hide misconfiguration. Still, we can change it if need be!
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.
We need config validation so this doesn't turn into a runtime failure at some indeterminate time after a configuration that refers to an unknown socket interface provider is specified.
Crashing the proxy in a situation like this doesn't seem like the right thing. Terminating the connection with some critical errors may be an option, but really - we need some protections during config load to provide some better guarantees that this won't happen.
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.
Currently, there's no way to configure a socket interface name on an address via config. The addresses have resolvers and resolvers spawn Address::Instance
s, with or without a socket interface name. So then, if the resolvers are misconfigured and generate broken addresses, what should we do?
But, let's assume we'll allow configuration of addresses with socket interface names and don't validate those in resolvers or wherever we spawn Address::Instance
s. Then, we could return nullptr IoHandlePtr
s or an IoSocketHandleImpl
with a -1 fd. Consequently, any place that constructs a Socket
must afterwards check if the internal IoHandle
was correctly initialized. A quick code check shows that ConnectionImpl
RELEASE_ASSERT
s that the socket it was given is valid in the constructor and similarly NetworkListenSocket
RELEASE_ASSERT
s that the IoHandle
's fd is valid.
Do we have any other alternatives?
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.
Possible idea: could we have the Address::Instance provide a const SocketInterface* instead of a name?
How are Address::Instance typically constructed? Via a factory that would take the socket interface name as part of its config? That factory resolving the SocketInterface as part of its config validation would allow us to catch missing factories at config validation time. It will probably even be less memory hungry since you wouldn't need to keep a copy of the socket interface name string in every Address::Instance.
I think this would allow address factories more easily verify consistency early on. A null SocketInterface returned by the address would result in this code going down the normal path.
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.
That's an interesting idea! It's definitely doable, assuming all the places that construct Address::Instance
s have access to the socket_interface.h
and therefore ability to lookup the SocketInterface
implementations. But I'll defer this to @yanavlasov as I'm sure he has more experience with this type of problems given #11618
Signed-off-by: Florin Coras <fcoras@cisco.com>
Signed-off-by: Florin Coras <fcoras@cisco.com> Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: Florin Coras fcoras@cisco.com
Risk Level: Low
Testing: unit tests
Docs Changes: n/a
Release Notes: n/a