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

config: v2 Address resolution using named resolver #1835

Merged
merged 16 commits into from
Oct 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/envoy/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,11 @@ envoy_cc_library(
name = "listener_interface",
hdrs = ["listener.h"],
)

envoy_cc_library(
name = "resolver_interface",
hdrs = ["resolver.h"],
deps = [
":address_interface",
],
)
12 changes: 11 additions & 1 deletion include/envoy/network/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ class Instance {
bool operator!=(const Instance& rhs) const { return !operator==(rhs); }

/**
* @return a human readable string for the address.
* @return a human readable string for the address that represents the
* physical/resolved address.
*
* This string will be in the following format:
* For IPv4 addresses: "1.2.3.4:80"
Expand All @@ -110,6 +111,15 @@ class Instance {
*/
virtual const std::string& asString() const PURE;

/**
* @return a human readable string for the address that represents the
* logical/unresolved name.
*
* This string has a source-dependent format and should preserve the original
* name for Address::Instances resolved by a Network::Address::Resolver.
*/
virtual const std::string& logicalName() const PURE;

/**
* Bind a socket to this address. The socket should have been created with a call to socket() on
* an Instance of the same address family.
Expand Down
40 changes: 40 additions & 0 deletions include/envoy/network/resolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <sys/types.h>

#include <cstdint>
#include <string>

#include "envoy/common/pure.h"
#include "envoy/network/address.h"

#include "api/address.pb.h"

namespace Envoy {
namespace Network {
namespace Address {

/**
* Interface for all network address resolvers.
*/
class Resolver {
public:
virtual ~Resolver() {}

/**
* Resolve a custom address string and port to an Address::Instance.
* @param socket_address supplies the socket address to resolve.
* @return InstanceConstSharedPtr appropriate Address::Instance.
*/
virtual InstanceConstSharedPtr resolve(const envoy::api::v2::SocketAddress& socket_address) PURE;

/**
* @return std::string the identifying name for a particular implementation of
* a resolver.
*/
virtual std::string name() const PURE;
};

} // namespace Address
} // namespace Network
} // namespace Envoy
25 changes: 21 additions & 4 deletions include/envoy/registry/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ template <class Base> class FactoryRegistry {
return it->second;
}

/**
* Remove a factory by name.
*/
static void unregisterFactory(Base& factory) {
auto result = factories().erase(factory.name());
if (result == 0) {
throw EnvoyException(fmt::format("No registration for name: '{}'", factory.name()));
}
}

private:
/**
* Gets the current map of factory implementations.
Expand Down Expand Up @@ -73,10 +83,17 @@ template <class T, class Base> class RegisterFactory {
/**
* Contructor that registers an instance of the factory with the FactoryRegistry.
*/
RegisterFactory() {
static T* instance = new T;
FactoryRegistry<Base>::registerFactory(*instance);
}
RegisterFactory() { FactoryRegistry<Base>::registerFactory(instance_); }

/**
* Destructor that removes an instance of the factory from the FactoryRegistry.
*/
~RegisterFactory() { FactoryRegistry<Base>::unregisterFactory(instance_); }
Copy link
Member

@mrice32 mrice32 Oct 12, 2017

Choose a reason for hiding this comment

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

This new setup creates a slightly bigger violation of the static ordering fiasco - we now have destructors being called in some unknown ordering (in addition to the constructors). @akonradi mentioned this was done so that tests don't leak state. Maybe it would be preferable to create an unregister method on the FactoryRegistry that manually removes the pointer (and allows the user to delete, maybe by returning as a std::unique_ptr) rather than doing it by default on destruction of the RegisterFactory class since we'd only need this in tests? @htuch thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

@akonradi can you point at the specific test where the leak was an issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

https://github.com/akonradi/envoy/blob/915c7d3b432ae9a4abbc4f69da5bf19694feb59a/test/common/network/resolver_impl_test.cc#L145 is where there could have been one if the resolver from https://github.com/akonradi/envoy/blob/915c7d3b432ae9a4abbc4f69da5bf19694feb59a/test/common/network/resolver_impl_test.cc#L106 was allowed to leak. FWIW it seems like we've avoided this in the rest of the tests because we don't register test factories and stick to testing the included ones.

Copy link
Member

Choose a reason for hiding this comment

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

This is where a singleton override for test would be useful. @alyssawilk any thoughts on how far along the work is to provide this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hasn't started (not assigned) but it looked like a pretty simple implementation. If it's as few lines of code as I think it could be folded in here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're talking about #1808? I'd rather make that a separate pull request and either wait to merge it once it lands in master or add a TODO here.

Copy link
Member

Choose a reason for hiding this comment

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

OK, TODO sounds good to me, and update the issue to reference, thanks.


T& testGetFactory() { return instance_; }

private:
T instance_;
};

} // namespace Registry
Expand Down
11 changes: 11 additions & 0 deletions source/common/config/well_known_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ class NetworkFilterNameValues {

typedef ConstSingleton<NetworkFilterNameValues> NetworkFilterNames;

/**
* Well-known address resolver names.
*/
class AddressResolverNameValues {
public:
// Basic IP resolver
const std::string IP = "envoy.ip";
};

typedef ConstSingleton<AddressResolverNameValues> AddressResolverNames;

/**
* Well-known http filter names.
*/
Expand Down
16 changes: 16 additions & 0 deletions source/common/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,22 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "resolver_lib",
srcs = ["resolver_impl.cc"],
hdrs = ["resolver_impl.h"],
external_deps = ["envoy_base"],
deps = [
":utility_lib",
"//include/envoy/network:address_interface",
"//include/envoy/network:resolver_interface",
"//include/envoy/registry",
"//source/common/config:well_known_names",
"//source/common/network:address_lib",
"//source/common/protobuf",
],
)

envoy_cc_library(
name = "utility_lib",
srcs = ["utility.cc"],
Expand Down
2 changes: 2 additions & 0 deletions source/common/network/address_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class InstanceBase : public Instance {
// Network::Address::Instance
bool operator==(const Instance& rhs) const override { return asString() == rhs.asString(); }
const std::string& asString() const override { return friendly_name_; }
// Default logical name is the human-readable name.
const std::string& logicalName() const override { return asString(); }
Type type() const override { return type_; }

protected:
Expand Down
75 changes: 75 additions & 0 deletions source/common/network/resolver_impl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "common/network/resolver_impl.h"

#include "envoy/common/exception.h"
#include "envoy/network/address.h"
#include "envoy/network/resolver.h"
#include "envoy/registry/registry.h"

#include "common/config/well_known_names.h"
#include "common/network/address_impl.h"
#include "common/network/utility.h"

#include "api/address.pb.h"

namespace Envoy {
namespace Network {
namespace Address {

/**
* Implementation of a resolver for IP addresses.
*/
class IpResolver : public Resolver {

public:
InstanceConstSharedPtr resolve(const envoy::api::v2::SocketAddress& socket_address) override {
switch (socket_address.port_specifier_case()) {
case envoy::api::v2::SocketAddress::kPortValue:
// Default to port 0 if no port value is specified.
case envoy::api::v2::SocketAddress::PORT_SPECIFIER_NOT_SET:
return Network::Utility::parseInternetAddress(socket_address.address(),
socket_address.port_value());

default:
throw EnvoyException(fmt::format("IP resolver can't handle port specifier type {}",
socket_address.port_specifier_case()));
}
}

std::string name() const override { return Config::AddressResolverNames::get().IP; }
};

/**
* Static registration for the IP resolver. @see RegisterFactory.
*/
static Registry::RegisterFactory<IpResolver, Resolver> ip_registered_;

InstanceConstSharedPtr resolveProtoAddress(const envoy::api::v2::Address& address) {
switch (address.address_case()) {
case envoy::api::v2::Address::kSocketAddress:
return resolveProtoSocketAddress(address.socket_address());
case envoy::api::v2::Address::kPipe:
return InstanceConstSharedPtr{new PipeInstance(address.pipe().path())};
default:
throw EnvoyException("Address must be a socket or pipe: " + address.DebugString());
}
}

InstanceConstSharedPtr
resolveProtoSocketAddress(const envoy::api::v2::SocketAddress& socket_address) {
Resolver* resolver = nullptr;
const std::string& resolver_name = socket_address.resolver_name();
if (resolver_name.empty()) {
resolver =
Registry::FactoryRegistry<Resolver>::getFactory(Config::AddressResolverNames::get().IP);
} else {
resolver = Registry::FactoryRegistry<Resolver>::getFactory(resolver_name);
}
if (resolver == nullptr) {
throw EnvoyException(fmt::format("Unknown address resolver: {}", resolver_name));
}
return resolver->resolve(socket_address);
}

} // namespace Address
} // namespace Network
} // namespace Envoy
30 changes: 30 additions & 0 deletions source/common/network/resolver_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "envoy/network/address.h"
#include "envoy/network/connection.h"
#include "envoy/network/resolver.h"

#include "common/network/address_impl.h"

#include "api/address.pb.h"

namespace Envoy {
namespace Network {
namespace Address {
/**
* Create an Instance from a envoy::api::v2::Address.
* @param address supplies the address proto to resolve.
* @return pointer to the Instance.
*/
Address::InstanceConstSharedPtr resolveProtoAddress(const envoy::api::v2::Address& address);

/**
* Create an Instance from a envoy::api::v2::SocketAddress.
* @param address supplies the socket address proto to resolve.
* @return pointer to the Instance.
*/
Address::InstanceConstSharedPtr
resolveProtoSocketAddress(const envoy::api::v2::SocketAddress& address);
} // namespace Address
} // namespace Network
} // namespace Envoy
19 changes: 0 additions & 19 deletions source/common/network/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,25 +146,6 @@ Address::InstanceConstSharedPtr Utility::copyInternetAddressAndPort(const Addres
return std::make_shared<Address::Ipv6Instance>(ip.addressAsString(), ip.port());
}

Address::InstanceConstSharedPtr Utility::fromProtoAddress(const envoy::api::v2::Address& address) {
switch (address.address_case()) {
case envoy::api::v2::Address::kSocketAddress:
return Utility::fromProtoSocketAddress(address.socket_address());
case envoy::api::v2::Address::kPipe:
return Address::InstanceConstSharedPtr{new Address::PipeInstance(address.pipe().path())};
default:
throw EnvoyException("Address must be a socket or pipe: " + address.DebugString());
}
}

Address::InstanceConstSharedPtr
Utility::fromProtoSocketAddress(const envoy::api::v2::SocketAddress& socket_address) {
// TODO(htuch): Support custom resolvers #1477.
ASSERT(socket_address.resolver_name().empty());
ASSERT(socket_address.named_port().empty());
return parseInternetAddress(socket_address.address(), socket_address.port_value());
}

void Utility::throwWithMalformedIp(const std::string& ip_address) {
throw EnvoyException(fmt::format("malformed IP address: {}", ip_address));
}
Expand Down
15 changes: 0 additions & 15 deletions source/common/network/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,6 @@ class Utility {
*/
static Address::InstanceConstSharedPtr parseInternetAddressAndPort(const std::string& ip_address);

/**
* Create an Instance from a envoy::api::v2::Address.
* @param address message.
* @return pointer to the Instance.
*/
static Address::InstanceConstSharedPtr fromProtoAddress(const envoy::api::v2::Address& address);

/**
* Create an Instance from a envoy::api::v2::SocketAddress.
* @param socket address message.
* @return pointer to the Instance.
*/
static Address::InstanceConstSharedPtr
fromProtoSocketAddress(const envoy::api::v2::SocketAddress& address);

/**
* Get the local address of the first interface address that is of type
* version and is not a loopback address. If no matches are found, return the
Expand Down
3 changes: 3 additions & 0 deletions source/common/upstream/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ envoy_cc_library(
"//source/common/http:async_client_lib",
"//source/common/http/http1:conn_pool_lib",
"//source/common/http/http2:conn_pool_lib",
"//source/common/network:resolver_lib",
"//source/common/network:utility_lib",
"//source/common/protobuf:utility_lib",
"//source/common/router:shadow_writer_lib",
Expand Down Expand Up @@ -218,6 +219,7 @@ envoy_cc_library(
"//source/common/config:utility_lib",
"//source/common/config:well_known_names",
"//source/common/network:address_lib",
"//source/common/network:resolver_lib",
"//source/common/network:utility_lib",
],
)
Expand Down Expand Up @@ -265,6 +267,7 @@ envoy_cc_library(
"//source/common/config:tls_context_json_lib",
"//source/common/http:utility_lib",
"//source/common/network:address_lib",
"//source/common/network:resolver_lib",
"//source/common/network:utility_lib",
"//source/common/protobuf",
"//source/common/protobuf:utility_lib",
Expand Down
3 changes: 2 additions & 1 deletion source/common/upstream/cluster_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "common/http/http1/conn_pool.h"
#include "common/http/http2/conn_pool.h"
#include "common/json/config_schemas.h"
#include "common/network/resolver_impl.h"
#include "common/network/utility.h"
#include "common/protobuf/utility.h"
#include "common/router/shadow_writer_impl.h"
Expand Down Expand Up @@ -196,7 +197,7 @@ ClusterManagerImpl::ClusterManagerImpl(const envoy::api::v2::Bootstrap& bootstra
}

if (bootstrap.cluster_manager().upstream_bind_config().has_source_address()) {
source_address_ = Network::Utility::fromProtoSocketAddress(
source_address_ = Network::Address::resolveProtoSocketAddress(
bootstrap.cluster_manager().upstream_bind_config().source_address());
}

Expand Down
3 changes: 2 additions & 1 deletion source/common/upstream/eds.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "common/config/utility.h"
#include "common/config/well_known_names.h"
#include "common/network/address_impl.h"
#include "common/network/resolver_impl.h"
#include "common/network/utility.h"
#include "common/upstream/sds_subscription.h"

Expand Down Expand Up @@ -60,7 +61,7 @@ void EdsClusterImpl::onConfigUpdate(const ResourceVector& resources) {
for (const auto& locality_lb_endpoint : cluster_load_assignment.endpoints()) {
for (const auto& lb_endpoint : locality_lb_endpoint.lb_endpoints()) {
new_hosts.emplace_back(new HostImpl(
info_, "", Network::Utility::fromProtoAddress(lb_endpoint.endpoint().address()),
info_, "", Network::Address::resolveProtoAddress(lb_endpoint.endpoint().address()),
lb_endpoint.metadata(), lb_endpoint.load_balancing_weight().value(),
locality_lb_endpoint.locality()));
}
Expand Down
Loading