network/config: Add IPv6 DNS support#1002
Conversation
|
@htuch @jamessynge for high level review and sanity check first |
| dns_loopkup_ip_version | ||
| *(optional, string)* The dns IP address version lookup policy. The options are *v4_only*, *v6_only*, | ||
| and *auto*. If this setting is not specified, the value defaults to *v4_only*. When *v4_only* is selected, | ||
| the dns resolver will only perform a lookup for addresses in the IPv4 family. If *v6_only* is selected, |
There was a problem hiding this comment.
Nit: s/dns/DNS/ at least in documentation/comments.
| } | ||
|
|
||
| void DnsResolverImpl::PendingResolution::getHostByName(int family) { | ||
| ares_gethostbyname(channel_, dns_name_.c_str(), |
There was a problem hiding this comment.
As discussed IRL last week, ares_gethostbyname() can implement the IPv6-IPv4 fallback with AF_UNSPEC family set (but is badly documented). However, I think your current implementation gets us closer to where we want to be in #978, since it will allow for the return of both IPv6 and IPv4 addresses in a list in a future PR, where we can support the caller deciding upon fallback as a result of connect() failure. So, I reckon it's good to keep the explicit fallback in this PR.
There was a problem hiding this comment.
It also seems that AF_UNSPEC has unexpected behavior (not a straightforward IPv6 lookup followed by a IPv4 lookup). Once that and returning multiple address types is added to the c-ares library, we can switch over to using AF_UNSPEC.
|
|
||
| .. _config_cluster_manager_cluster_dns_lookup_ip_version: | ||
|
|
||
| dns_loopkup_ip_version |
| */ | ||
| virtual ActiveDnsQuery* resolve(const std::string& dns_name, ResolveCb callback) PURE; | ||
| virtual ActiveDnsQuery* resolve(const std::string& dns_name, | ||
| const std::string& dns_lookup_ip_version, |
There was a problem hiding this comment.
Instead of passing the dns_lookup_ip_version as a string, consider resolving it into an enum when you process the configuration and use that enum here. This will be cheaper than doing the string comparisons every time you resolve.
|
Updated. PTAL. |
htuch
left a comment
There was a problem hiding this comment.
The core ares code looks good, but there's a dangerous side condition to fix :)
| virtual void cancel() PURE; | ||
| }; | ||
|
|
||
| enum class DnsLookupFamily { v4_only, v6_only, fallback }; |
There was a problem hiding this comment.
Nit: CAPS for enums for consistency:
There was a problem hiding this comment.
It seems there are enums with all caps (https://github.com/lyft/envoy/blob/998b8119ed57269e77d0a03b1b92e7a98c5d30d1/source/server/config/network/http_connection_manager.h#L114) but also many cases of not all caps (https://github.com/lyft/envoy/blob/998b8119ed57269e77d0a03b1b92e7a98c5d30d1/source/server/config/network/http_connection_manager.h#L24) Which is the convention?
There was a problem hiding this comment.
This came up in another PR recently: https://github.com/lyft/envoy/pull/989/files/431c909dcd7d70686cc9986c9ef019bef8942ae2#r117533920
I think we are going with all-caps. Feel free to create a https://github.com/lyft/envoy/blob/master/STYLE.md to codify.
| */ | ||
| virtual ActiveDnsQuery* resolve(const std::string& dns_name, ResolveCb callback) PURE; | ||
| virtual ActiveDnsQuery* resolve(const std::string& dns_name, | ||
| const DnsLookupFamily& dns_lookup_family, |
There was a problem hiding this comment.
I would just pass this by value, it might even be more efficient to do so (it's just a small integer).
| }, | ||
| "dns_lookup_family" : { | ||
| "type" : "string", | ||
| "enum" : ["v4_only", "v6_only", "auto"] |
There was a problem hiding this comment.
Docs say fallback, but it's auto here.
There was a problem hiding this comment.
I actually, like 'auto' for consistency with other settings (just fix the doc)
There was a problem hiding this comment.
The problem with auto is that it's a keyword and can't be used when making the string to enum conversion.
There was a problem hiding this comment.
Actually AUTO might be okay
| address.sin6_family = AF_INET6; | ||
| address.sin6_port = 0; | ||
| address.sin6_addr = *reinterpret_cast<in6_addr*>(hostent->h_addr_list[i]); | ||
| address_list.emplace_back(new Address::Ipv6Instance(address)); |
There was a problem hiding this comment.
Unrelated to your review, but it seems weird that the sockeadd[_in6] constructors for Ipv4Instance and Ipv6Instance differ in whether they take a pointer or reference.
| getHostByName(AF_INET); | ||
| } | ||
| if (!cancelled_) { | ||
| if (!cancelled_ && completed_) { |
There was a problem hiding this comment.
Nit: You can move both if clauses under a if (completed_) {.
| ResolveCb callback) { | ||
| std::unique_ptr<PendingResolution> pending_resolution(new PendingResolution()); | ||
| pending_resolution->callback_ = callback; | ||
| pending_resolution->channel_ = channel_; |
There was a problem hiding this comment.
As a cleanup to my earlier mess, you could make all of these constructor args and initialize them in the constructor's member initializor list, allowing them to be made const.
| } | ||
| } else if (fallback_if_failed) { | ||
| fallback_if_failed = false; | ||
| getHostByName(AF_INET); |
There was a problem hiding this comment.
I think there's a dangerous corner case here. If the first getHostByName() defers to asynch completion but then the fallback getHostByName() succeeds immediately (synchronously), it will invoke the callback, which will delete this;. This will then return to the caller method belonging to a now deleted object.
| }, | ||
| "dns_lookup_family" : { | ||
| "type" : "string", | ||
| "enum" : ["v4_only", "v6_only", "auto"] |
There was a problem hiding this comment.
I actually, like 'auto' for consistency with other settings (just fix the doc)
| ares_gethostbyname(channel_, dns_name_.c_str(), | ||
| family, [](void* arg, int status, int timeouts, hostent* hostent) { | ||
| static_cast<PendingResolution*>(arg)->onAresHostCallback(status, hostent); | ||
| UNREFERENCED_PARAMETER(timeouts); |
There was a problem hiding this comment.
i think you should be able to (void arg, int status, int, hostent hostent) and remove UNREFERENCED_PARAMETER.
| ares_channel channel_; | ||
| std::string dns_name_; | ||
|
|
||
| void getHostByName(int family); |
There was a problem hiding this comment.
nit: put this right after void onAresHostCallback(int status, hostent* hostent);
| } else if (dns_lookup_family == "fallback") { | ||
| dns_lookup_family_ = Network::DnsLookupFamily::fallback; | ||
| } else { | ||
| dns_lookup_family_ = Network::DnsLookupFamily::v4_only; |
There was a problem hiding this comment.
for being on a defensive side can you assert here that dns_lookup_family is equal to "v4_only".
| throw EnvoyException("logical_dns clusters must have a single host"); | ||
| } | ||
|
|
||
| // Resolve string to enum. |
There was a problem hiding this comment.
up to you, but the comment does not add value, it's pretty straightforward what's happening here
| // TODO(mattklein123): Move port handling into the DNS interface. | ||
| Network::Address::IpVersion version = address_list.front()->ip()->version(); | ||
| Network::Address::InstanceConstSharedPtr new_address; | ||
| if (version == Network::Address::IpVersion::v4) { |
There was a problem hiding this comment.
can you do switch here, so we make sure that compiler will complain in case enum values changes (with low probability though :))
| // want to do better again later. | ||
| logical_host_.reset(new LogicalHost( | ||
| info_, hostname_, Network::Utility::resolveUrl("tcp://0.0.0.0:0"), *this)); | ||
| if (version == Network::Address::IpVersion::v4) { |
htuch
left a comment
There was a problem hiding this comment.
This is close to being ready to merge once the comments are solved. @RomanDzhabarov do you have any further comments?
| includes both const and non-const references. | ||
| * Function names using camel case starting with a lower case letter (e.g., "doFoo()"). | ||
| * Struct/Class member variables have a '\_' postfix (e.g., "int foo\_;"). | ||
| * Enum values using all CAPS (e.g., "EXTERNAL_ONLY"). |
There was a problem hiding this comment.
Thanks. Small nit: use back ticks to quote, e.g. EXTERNAL_ONLY.
There was a problem hiding this comment.
hm, I'm not sure about this.
grep -ir 'enum class' gives the majority of the enum values in PascalCase.
Any particular reason we want to stick to the all CAPS?
There was a problem hiding this comment.
It actually looks like #989 was referring to static const values. However, there are also cases of all CAPS enums in the code.
| "dns_refresh_rate_ms": "...", | ||
| "outlier_detection": "{...}" | ||
| "dns_lookup_family": "...", | ||
| "outlier_detection": "..." |
There was a problem hiding this comment.
I think you undid #1010 here, can you revert the change to the "outlier_detection" line?
| bool cancelled_ = false; | ||
| // If dns_lookup_family is "fallback", fallback to v4 address if v6 | ||
| // resolution failed. | ||
| bool fallback_if_failed = false; |
| fallback_if_failed = false; | ||
| getHostByName(AF_INET); | ||
| // Note: Nothing can follow this call to getHostByName due to deletion of this | ||
| // object upon synchronous resolution. |
There was a problem hiding this comment.
Maybe add an explicit return; after the comment to make this even clearer.
| // TODO(mattklein123): Move port handling into the DNS interface. | ||
| Network::Address::IpVersion version = address_list.front()->ip()->version(); | ||
| Network::Address::InstanceConstSharedPtr new_address; | ||
| switch (version) { |
There was a problem hiding this comment.
This stuff can probably be factored out. You can add to Network::Address::Instance a withPort(int port) method that returns a new address with the port replaced as done here.
| parent_.info_, dns_address_, | ||
| Network::Address::InstanceConstSharedPtr{ | ||
| new Network::Address::Ipv6Instance(address->ip()->addressAsString(), port_)}, | ||
| false, 1, "")); |
| EXPECT_CALL(*resolve_timer_, enableTimer(_)); | ||
| cb(TestUtility::makeDnsResponse({"::1"})); | ||
| return nullptr; | ||
| })); |
There was a problem hiding this comment.
There might be an argument for using TEST_P here, but I'm not sure it's worth the effort and it's probably more readable the way you've done it.
| dispatcher); | ||
| cluster.setInitializedCb([&]() -> void { initialized.ready(); }); | ||
| EXPECT_EQ(2UL, cluster.hosts().size()); | ||
| EXPECT_EQ(2UL, cluster.healthyHosts().size()); |
There was a problem hiding this comment.
Actually, I think for these bigger examples, TEST_P would make more sense. You can make the parameter a std::tuple of string for the dns_lookup_family, DNS family and the DNS response list.
| EXPECT_EQ(2UL, cluster.healthyHosts().size()); | ||
| } | ||
|
|
||
| TEST(StrictDnsClusterImplTest, ImmediateResolveV6Only) { |
There was a problem hiding this comment.
Is there also LogicalDnsClusterImplTest?
There was a problem hiding this comment.
Yes, there's a logical_dns_cluster_test.cc
|
@htuch let me make the last pass also |
| return any; | ||
| } | ||
|
|
||
| Address::InstanceConstSharedPtr Utility::getAddressUpdatePort(const Address::Instance& address, |
|
I think mattklein123@ advocated for this in
#989 (comment). I don't have
a strong opinion as long as we are consistent with this and document.
…On Wed, May 24, 2017 at 11:27 AM Roman Dzhabarov ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In STYLE.md
<#1002 (comment)>:
> @@ -17,6 +17,7 @@
includes both const and non-const references.
* Function names using camel case starting with a lower case letter (e.g., "doFoo()").
* Struct/Class member variables have a '\_' postfix (e.g., "int foo\_;").
+* Enum values using all CAPS (e.g., "EXTERNAL_ONLY").
hm, I'm not sure about this.
grep -ir 'enum class' gives the majority of the enum values in PascalCase.
Any particular reason we want to stick to the all CAPS?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1002 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AKaLv0kMQ1fkCskjNJaOj9tpezgaX5EPks5r9HaigaJpZM4NhBDq>
.
|
| } | ||
|
|
||
| // c-ares ares_gethostbyname() query callback. | ||
| /* c-ares ares_gethostbyname() query callback. |
There was a problem hiding this comment.
nit: add /** before this line
| * @param hostent structure that stores information about a given host. | ||
| */ | ||
| void onAresHostCallback(int status, hostent* hostent); | ||
| /* wrapper function of call to ares_gethostbyname. |
There was a problem hiding this comment.
nit: add /** before this line
|
+1 |
Description: Adds invocation path for Android platform-bridged filters, covering request/response headers, data, and trailers. This change does not provide for state modification via the return path. Risk Level: Moderate Testing: Local and CI Signed-off-by: Mike Schore <mike.schore@gmail.com> Signed-off-by: JP Simard <jp@jpsim.com>
Description: Adds invocation path for Android platform-bridged filters, covering request/response headers, data, and trailers. This change does not provide for state modification via the return path. Risk Level: Moderate Testing: Local and CI Signed-off-by: Mike Schore <mike.schore@gmail.com> Signed-off-by: JP Simard <jp@jpsim.com>
**Description** This removes the unused "schema" API from AIGatewayRoute as a preparation for transparent passthrough etc support for non-OpenAI SDK support as well as the prefix configuration #1002 **Related Issues/PRs (if applicable)** Follow up on #998 Necessary for #1002 --------- Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
**Description** This commit makes the "prefix" for the supported endpoints configurable via global configurations. **Related Issues/PRs (if applicable)** Closes #1002 --------- Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This PR adds IPv6 DNS support and adds a cluster config parameter "dns_lookup_ip_version" that specifies the DNS lookup IP address policy. The default policy if no parameter is specified is "v4_only".
Modifications were made to upstream_cluster and logical_dns_cluster to pass this parameter on when calling DnsResolver resolve. Modifications were made to dns_impl to add v6 support and also a fallback option when v4 dns lookup fails.
Fixes #978 .