Skip to content

network/config: Add IPv6 DNS support#1002

Merged
htuch merged 13 commits intoenvoyproxy:masterfrom
hennna:dns-ipv6-support
May 25, 2017
Merged

network/config: Add IPv6 DNS support#1002
htuch merged 13 commits intoenvoyproxy:masterfrom
hennna:dns-ipv6-support

Conversation

@hennna
Copy link
Copy Markdown
Contributor

@hennna hennna commented May 19, 2017

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 .

@hennna
Copy link
Copy Markdown
Contributor Author

hennna commented May 19, 2017

@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,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: s/dns/DNS/ at least in documentation/comments.

}

void DnsResolverImpl::PendingResolution::getHostByName(int family) {
ares_gethostbyname(channel_, dns_name_.c_str(),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

loopkup -> lookup

Comment thread include/envoy/network/dns.h Outdated
*/
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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

@hennna
Copy link
Copy Markdown
Contributor Author

hennna commented May 22, 2017

Updated. PTAL.

Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

The core ares code looks good, but there's a dangerous side condition to fix :)

Comment thread include/envoy/network/dns.h Outdated
virtual void cancel() PURE;
};

enum class DnsLookupFamily { v4_only, v6_only, fallback };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: CAPS for enums for consistency:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread include/envoy/network/dns.h Outdated
*/
virtual ActiveDnsQuery* resolve(const std::string& dns_name, ResolveCb callback) PURE;
virtual ActiveDnsQuery* resolve(const std::string& dns_name,
const DnsLookupFamily& dns_lookup_family,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Docs say fallback, but it's auto here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually, like 'auto' for consistency with other settings (just fix the doc)

Copy link
Copy Markdown
Contributor Author

@hennna hennna May 22, 2017

Choose a reason for hiding this comment

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

The problem with auto is that it's a keyword and can't be used when making the string to enum conversion.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

bummer :(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread source/common/network/dns_impl.cc Outdated
getHostByName(AF_INET);
}
if (!cancelled_) {
if (!cancelled_ && completed_) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: You can move both if clauses under a if (completed_) {.

Comment thread source/common/network/dns_impl.cc Outdated
ResolveCb callback) {
std::unique_ptr<PendingResolution> pending_resolution(new PendingResolution());
pending_resolution->callback_ = callback;
pending_resolution->channel_ = channel_;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread source/common/network/dns_impl.cc Outdated
}
} else if (fallback_if_failed) {
fallback_if_failed = false;
getHostByName(AF_INET);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually, like 'auto' for consistency with other settings (just fix the doc)

Comment thread source/common/network/dns_impl.cc Outdated
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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

i think you should be able to (void arg, int status, int, hostent hostent) and remove UNREFERENCED_PARAMETER.

Comment thread source/common/network/dns_impl.h Outdated
ares_channel channel_;
std::string dns_name_;

void getHostByName(int family);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ditto

@RomanDzhabarov RomanDzhabarov self-assigned this May 22, 2017
Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

This is close to being ready to merge once the comments are solved. @RomanDzhabarov do you have any further comments?

Comment thread STYLE.md Outdated
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").
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks. Small nit: use back ticks to quote, e.g. EXTERNAL_ONLY.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Contributor Author

@hennna hennna May 24, 2017

Choose a reason for hiding this comment

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

It actually looks like #989 was referring to static const values. However, there are also cases of all CAPS enums in the code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yeah, I'd do Pascal and create an issue to clean up all of the enum values which do not conform this rule (Those are mostly have HTTPX form)

@Henna @htuch what would you say?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SGTM

"dns_refresh_rate_ms": "...",
"outlier_detection": "{...}"
"dns_lookup_family": "...",
"outlier_detection": "..."
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you undid #1010 here, can you revert the change to the "outlier_detection" line?

Comment thread source/common/network/dns_impl.h Outdated
bool cancelled_ = false;
// If dns_lookup_family is "fallback", fallback to v4 address if v6
// resolution failed.
bool fallback_if_failed = false;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

fallback_if_failed_

fallback_if_failed = false;
getHostByName(AF_INET);
// Note: Nothing can follow this call to getHostByName due to deletion of this
// object upon synchronous resolution.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread source/common/upstream/upstream_impl.cc Outdated
parent_.info_, dns_address_,
Network::Address::InstanceConstSharedPtr{
new Network::Address::Ipv6Instance(address->ip()->addressAsString(), port_)},
false, 1, ""));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As mentioned above.

EXPECT_CALL(*resolve_timer_, enableTimer(_));
cb(TestUtility::makeDnsResponse({"::1"}));
return nullptr;
}));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there also LogicalDnsClusterImplTest?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, there's a logical_dns_cluster_test.cc

@RomanDzhabarov
Copy link
Copy Markdown
Member

@htuch let me make the last pass also

htuch
htuch previously approved these changes May 24, 2017
Comment thread source/common/network/utility.cc Outdated
return any;
}

Address::InstanceConstSharedPtr Utility::getAddressUpdatePort(const Address::Instance& address,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Prefer addressWithPort.

@htuch
Copy link
Copy Markdown
Member

htuch commented May 24, 2017 via email

htuch
htuch previously approved these changes May 24, 2017
Comment thread source/common/network/dns_impl.h Outdated
}

// c-ares ares_gethostbyname() query callback.
/* c-ares ares_gethostbyname() query callback.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: add /** before this line

Comment thread source/common/network/dns_impl.h Outdated
* @param hostent structure that stores information about a given host.
*/
void onAresHostCallback(int status, hostent* hostent);
/* wrapper function of call to ares_gethostbyname.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: add /** before this line

@RomanDzhabarov
Copy link
Copy Markdown
Member

+1

@htuch htuch merged commit fd81bdd into envoyproxy:master May 25, 2017
@hennna hennna deleted the dns-ipv6-support branch May 31, 2017 16:26
jpsim pushed a commit that referenced this pull request Nov 28, 2022
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>
jpsim pushed a commit that referenced this pull request Nov 29, 2022
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>
mathetake added a commit that referenced this pull request Mar 3, 2026
**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>
mathetake added a commit that referenced this pull request Mar 3, 2026
**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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DnsResolver v4/v6 selection

6 participants