Skip to content

Listener: Add listener filters.#2346

Merged
mattklein123 merged 49 commits intoenvoyproxy:masterfrom
jrajahalme:listener-filters
Jan 23, 2018
Merged

Listener: Add listener filters.#2346
mattklein123 merged 49 commits intoenvoyproxy:masterfrom
jrajahalme:listener-filters

Conversation

@jrajahalme
Copy link
Copy Markdown
Contributor

Network::ListenerImpl class implements an libevent socket
listener. Factor out all functionality that is not directly libevent
related to ConnectionHandlerImpl, which both reduces overall
complexity and makes it possible to refactor configurable listener
behavior to a new class of listener filters in the following patches.

This patch also reduces the special handling for SSL connections by
introducing a new dispatcher member for creating server
connections. This is used by the refactored code as the connection
creation is now shifted from Network::Listener to the connection
handler.

To further simplify the resulting code, this patch removes
Network::ListenerOptions class, as the only option that now needs to
be passed to Network::Listener is the "bind to port" boolean, which is
now passed in explicitly. All other listener options are handled by
passing along Server::Listener instead.

Add support for listener filters and refactor listener original dst
and proxy protocol features as listener filters.

Existing use_proxy_protocol and use_original_dst listener flags are
still supported by internally converting them to listener filters.

Signed-off-by: Jarno Rajahalme jarno@covalent.io

Risk Level: High
Testing: Existing unit tests are converted to use the new filter framework where applicable.
Docs Changes: TBD
Release Notes: TBD
API Changes: [Data Plane PR #400][https://github.com/envoyproxy/data-plane-api/pull/400]
Deprecated: TBD if the legacy flags should be removed from v2 API

Network::ListenerImpl class implements an libevent socket
listener. Factor out all functionality that is not directly libevent
related to ConnectionHandlerImpl, which both reduces overall
complexity and makes it possible to refactor configurable listener
behavior to a new class of listener filters in the following patches.

This patch also reduces the special handling for SSL connections by
introducing a new dispatcher member for creating server
connections. This is used by the refactored code as the connection
creation is now shifted from Network::Listener to the connection
handler.

To further simplify the resulting code, this patch removes
Network::ListenerOptions class, as the only option that now needs to
be passed to Network::Listener is the "bind to port" boolean, which is
now passed in explicitly.  All other listener options are handled by
passing along Server::Listener instead.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Add support for listener filters and refactor listener original dst
and proxy protocol features as listener filters.

Existing use_proxy_protocol and use_original_dst listener flags are
still supported by internally converting them to listener filters.

As a further step we could remoe the legacy flags from the v2 APIs.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
@mattklein123
Copy link
Copy Markdown
Member

@PiotrSikora FYI this will have implications for the changes we were discussing today. I would wait for this to land first, otherwise you will need to rebase again. I will review this tomorrow.

@PiotrSikora
Copy link
Copy Markdown
Contributor

@lizan Could you take a look and see if this conflicts or helps with your work on transport security?

@jrajahalme
Copy link
Copy Markdown
Contributor Author

jrajahalme commented Jan 11, 2018 via email

@mattklein123
Copy link
Copy Markdown
Member

I briefly looked into the possibility of implementing SSL as a listener filter. IMO it seems possible using https://github.com/libevent/libevent/blob/master/bufferevent_openssl.c https://github.com/libevent/libevent/blob/master/bufferevent_openssl.c as long as Buffers will be evbuffers.

We won't be going back to bufferevent, but @lizan is working on a bunch of refactoring around pluggable transport layers, and @PiotrSikora is working on sniffing TLS so that we can do filter chain matching based on sniffed data. (Basically have a listener support both plain-text and TLS). Then I'm working on v2 filter chain matching.

We just need to be careful here to line everything up. I'm hopeful we can sort it out in comments but it's possible we will need to have a quick meeting. Let's see how things go in comments tomorrow.

@lizan
Copy link
Copy Markdown
Member

lizan commented Jan 11, 2018

Took a rough pass on the PR, some of this PR (e.g. deleting addSslListener from dispatcher) will help me for upstream transport socket, and I don't think it really add difficulty. One thing that needs clarification is when a listener filter read/write from/to the fd, it might conflict with what the transport socket do later.

Though this certainly conflicts with my local working directory. I'd like to know how long this is going to take to merge, to better lining things up.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
@mattklein123
Copy link
Copy Markdown
Member

@lizan I would like to move this along since it needs to come in front of a bunch of other items we are all working on. I've gotten derailed by a few things today so reviewing this might not happen but I will review later or tomorrow. We will aim to iterate and merge this early next week.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
@lizan
Copy link
Copy Markdown
Member

lizan commented Jan 11, 2018

@mattklein123 SGTM, I'll hold my changes for a few days :)

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
@jrajahalme
Copy link
Copy Markdown
Contributor Author

I still have some fixing left due to the rebase, will sort out tomorrow. Should not block reviewing, though.

Change info to debubg level.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

@jrajahalme this is a pretty epic change! In general, I really like the direction. Thanks for working on this. This is going to take multiple passes. I have some comments to get started. I would like to figure out interface stuff first and kill v1 support from the PR. Once we sort out interfaces, we can dive into the implementation. I think it would be helpful to actually provide a bit of a more detailed overview of what the new interface hierarchy is, as it would help with review and sorting out the common/server interface issues.

* @param accept_socket supplies a socket with an open file descriptor and connection metadata
* to use for the connection. Takes ownership of the accept_socket.
* @param ssl_ctx supplies the SSL context to use, if not nullptr.
* @return Network::ConnectionPtr a client connection that is owned by the caller.
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.

"a server connection"

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.

Fixed!

* @param ssl_ctx supplies the SSL context to use, if not nullptr.
* @return Network::ConnectionPtr a client connection that is owned by the caller.
*/
virtual Network::ConnectionPtr createConnection(Network::AcceptSocketPtr&& accept_socket,
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 probably call this createServerConnection to match createClientConnection

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.

Will change.

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.

There is no ServerConnection class, ClientConnection inherits from Connection, so from that viewpoint createConnection() is correct. Hosts also have a createConnection method, so createServerConnection makes grepping the source easier.

createSslListener(Network::ConnectionHandler& conn_handler, Ssl::ServerContext& ssl_ctx,
Network::ListenSocket& socket, Network::ListenerCallbacks& cb,
Stats::Scope& scope, const Network::ListenerOptions& listener_options) PURE;
virtual Network::ListenerPtr createListener(Network::ListenSocket& socket,
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.

please fix doc comments above

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.

OK, sorry for the sloppiness...

namespace Server {
class Listener;
}
// XXX: Move to Server namespace?
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, from an abstraction level in general we try to make server code depend on common code, but not the other way around. Why was this necessary?

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.

Listener config is defined in the Server namespace (Server::Listener), and the ConnectionHandler's addListener() now takes it as an argument. I did not want to include server headers from here, so I used a bare class declaration (in the correct namespace) to circumvent the need for the include.

Could also see if the Listener config class could be moved to the common 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, let's just move Server::Listener (that interface only) into the Network namespace. That interface doesn't depend on anything else in Server. Please do that in a dedicated PR since it will be just code movement. We can review/merge that quickly and then rebase this.

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.

Network namespace already has a Listener (the abstract base class, so something needs to be renamed. How about renaming the Server::Listener as Network::ListenerConfig, as it is just that, "A configuration for an individual listener", as the comment says?

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.

+1

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.

Will do this and the filter directory split tomorrow, hopefully. In the meanwhile I updated this PR so that you may continue the review as you please :-)

virtual Event::Dispatcher& dispatcher() PURE;

/**
* If an filter stopped filter iteration by returning FilterStatus::StopIteration,
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.

"a filter"

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.

Thanks.

const std::string PROXY_PROTOCOL = "envoy.proxy_protocol";

// Converts names from v1 to v2
const V1Converter v1_converter_;
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.

v2 only please

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.

OK.

return fd;
}

void clearReset() override { local_address_reset_ = 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.

This existence/semantics of the clearReset() function is strange to me. It doesn't apply to remote, and it leaves the addresses to what they were reset to. This feels like a hack to me. Can you explain why this is needed and if there is a cleaner way to handle the need?

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.

I was never happy with the name of this function either.

This is needed for handing off the accepted socket from one listener to another, which is needed for backwards compatibility in the case where the first listener listens on a redirected port and the second listener matches the original local address but does not bind.

Clearing of the local_address_reset_ bit is needed so that the second listener would not try to repeat the same check again (in an infinite recursion). See the call site in source/server/connection_handler_impl.cc.

This implementation also allows the second listener have and run it's own set of listener filters on the accepted socket it is given.

So the functionality is correct and needed. We should rename this function to lessen the likelihood of confusion in the future, though.

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.

OK. I would probably switch reset with "change" and use the following function names (or some variant of them):

  1. changeLocalAddress(...)
  2. localAddressChanged()
  3. forgetOriginalLocalAddress() (This should ASSERT that the local address was changed when called).

Etc.

And more heavily comment the interface. Feel free to iterate on my suggestions above, but that is more clear to me.

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.

Just realized that the resetting the local_address_reset_ bit when passing the socket from one listener to another would break the original dst cluster from being able to forward the connection, so I'll have to figure alternative way of not recursing from the second listener. I don't see a need for using an original destination cluster in conjunction of non-bound listeners like this, but I don't like the way this is now anyway, so I'll spend some time on this. I'll try to come up with something that also addresses your concerns here and does not need heavy commenting :-)

@@ -0,0 +1,47 @@
#include <string>
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.

Please move the configs to a listener folder, like the filters.

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.

Will do.

~ActiveListener();

// Network::ListenerCallbacks
/**
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: don't need to duplicate doc comments here

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.

Made them more specific.

string_name);
if (factory != nullptr) {
Configuration::ListenerFilterFactoryCb callback;
if (filter_config->getBoolean("deprecated_v1", 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.

v2 only please

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.

Done.

@ggreenway
Copy link
Copy Markdown
Member

I looked through this, and I wonder if it should be reworked so that there is a connection object of some type (a thing to hold the fd, and handle reading from it) is created as soon as the connection is accepted. It would then call the new set of filters, then match which logical listener and/or filter chain to use, then proceed.

The piece about this I dislike, which made me think of the above, is that the proxy protocol filter has to implement reading from the socket directly. I imagine other listener filters will need to do the same.

The other thing I think we'll want eventually, is for one of these new filters to read some data, look at it, and then pass it along (modified or not) to the network filters. This could be done with MSG_PEEK, but that seems like a hack.

Thoughts?

@mattklein123
Copy link
Copy Markdown
Member

mattklein123 commented Jan 12, 2018

The piece about this I dislike, which made me think of the above, is that the proxy protocol filter has to implement reading from the socket directly. I imagine other listener filters will need to do the same.

Yes hiding the fd behind some interface (possibly not the full connection interface, something like PreConnectionHandle or something SGTM. I don't think though that it changes the overall architecture of the PR, but I agree it would be an improvement over what we were doing previously.

@mattklein123 mattklein123 self-assigned this Jan 12, 2018
* @param context supplies the filter's context.
* @return ListenerFilterFactoryCb the factory creation function.
*/
virtual ListenerFilterFactoryCb createFilterFactory(const Json::Object& config,
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.

If we go v2 only, no necessary of this method

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.

OK, removed.

* JSON and then parsed into this empty proto. Optional today, will be compulsory when v1
* is deprecated.
*/
virtual ProtobufTypes::MessagePtr createEmptyConfigProto() { 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.

this should be a PURE method.

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.

Right, fixed!

}

ProtobufTypes::MessagePtr createEmptyConfigProto() override {
return ProtobufTypes::MessagePtr{new Envoy::ProtobufWkt::Empty()};
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: std::make_unique

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.

Envoy::ProtobufWkt::Empty() is a more specific type than ProtobufTypes::Message, do you think using std::make_unique would make this easier on the eyes?

ActiveListenerPtr l(new SslActiveListener(*this, ssl_ctx, socket, factory, scope, listener_tag,
listener_options));
listeners_.emplace_back(socket.localAddress(), std::move(l));
void ConnectionHandlerImpl::addListener(Listener& config) {
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 for consolidating addListner and addSslListener, neat!

/**
* Wrapper for an active accept socket owned by this handler.
*/
struct ActiveSocket : public Network::ListenerFilterManager,
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: this still have to be a class, per Google Style Guide (no deviation in envoy style for this):

Use a struct only for passive objects that carry data; everything else is a class.

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.

I tried this but this happened even when I made all members public:

source/server/connection_handler_impl.cc: In destructor 'virtual Envoy::Server::ConnectionHandlerImpl::ActiveListener::~ActiveListener()':
source/server/connection_handler_impl.cc:72:72: error: 'std::unique_ptr<_Tp> Envoy::LinkedObject<T>::removeFromList(Envoy::LinkedObject<T>::ListType&) [with T = Envoy::Server::ConnectionHandlerImpl::ActiveSocket; Envoy::LinkedObject<T>::ListType = std::__cxx11::list<std::unique_ptr<Envoy::Server::ConnectionHandlerImpl::ActiveSocket> >]' is inaccessible within this context
     ActiveSocketPtr removed = sockets_.front()->removeFromList(sockets_);

Maybe there is a reason other structs like this also exist in this file?

Configuration::FactoryContext& context) {
std::vector<Configuration::ListenerFilterFactoryCb> ret;
for (ssize_t i = 0; i < filters.size(); i++) {
const std::string string_type = filters[i].deprecated_v1().type();
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: ProtobufTypes::String

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.

Fixed.

// Server::ListenSocketFactory
// Server::ListenerComponentFactory
std::vector<Configuration::NetworkFilterFactoryCb>
createFilterFactoryList(const Protobuf::RepeatedPtrField<envoy::api::v2::Filter>& filters,
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.

rename this to createNetworkFilterFactoryList?

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.

OK.

* @return true if filter chain was created successfully. Otherwise
* false.
*/
virtual bool createFilterChain(ListenerFilterManager& listener) PURE;
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.

createListnerFilterChain for this and createNetworkFilterChain for the one above, this shouldn't be an overloaded.

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.

OK.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Sync with the API change to a separate ListenerFilter type.

Drop API v1 support.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Rename createConnection() as createServerConnection(), rhymes with
createClientConnection().

Requested-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Requested-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Some of the tests depended on the timing of data arraving to the
socket read by the proxy protocol filter. Make all tests run the
dispatcher in blocking mode, and stop the dispatcher when we know that
the proxy protocol processing has finished.

These changes allow these tests to pass on OSX, and also prevent
spurious test failures on other platforms.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
@jrajahalme
Copy link
Copy Markdown
Contributor Author

Proxy protocol tests depended on OS timing w.r.t socket buffering and I/O. Converted tests that did this to run the dispatched until the read filter gets callbacks to make the test runs deterministic. With this I got the proxy protocol test succeed locally on Mac as well as Linux.

@jrajahalme
Copy link
Copy Markdown
Contributor Author

jrajahalme commented Jan 22, 2018 via email

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks, this is a really awesome change. I love the way that it cleans up a bunch of special case logic. I just have a random assortment of minor comments. Let's finalize the data-plane-api PR and then we can close this out and get it merged!

* different from the one the socket was initially accepted at. This should only be set
* to 'true' when restoring the original destination address of a connection redirected
* by iptables REDIRECT. The caller is responsible for making sure the new address is
* actually different when passing restored as 'true'.
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 also give an example of when someone would call this function but set restored to false? I see multiple examples in this PR but just from reading the interfaces it's not completely clear when one would do that.

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.

I reverted the meaning of this boolean and renamed it as "hand_off_restored_destinations", should be clearer now, see the new commit.

*/
bool readLine(int fd, std::string& s);

Network::ListenerFilterCallbacks* cb_;
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.

initialize to {}

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.

Done.

size_t buf_off_{};

// The index in buf_ where the search for '\r\n' should continue from
size_t search_index_;
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.

not your code but I would move the {1} initializer here 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.

OK.

: ConnectionImpl(dispatcher, std::make_unique<ClientSocketImpl>(remote_address),
std::move(transport_socket), false) {
if (source_address != nullptr) {
int rc = source_address->bind(fd());
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: const

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.

OK.


void ClientConnectionImpl::connect() {
ENVOY_CONN_LOG(debug, "connecting to {}", *this, socket_->remoteAddress()->asString());
int rc = socket_->remoteAddress()->connect(fd());
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: const

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.

Ditto.

// Purge sockets that have not progressed to connections. This should only happen when
// a listener filter stops iteration and never resumes.
while (!sockets_.empty()) {
ActiveSocketPtr removed = sockets_.front()->removeFromList(sockets_);
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.

Do you have test coverage for this case?

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.

proxy_protocol_test.cc should exercise this, it has tests for invalid/truncated proxy protocol messages.


ActiveListener& listener_;
Network::ConnectionSocketPtr socket_;
bool redirected_;
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.

const

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.

OK.

// filter chain #1308.
ASSERT(config.filter_chains().size() >= 1);

if (config.listener_filters().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.

nit: !config.listener_filters().empty()

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.

OK.

listener_filter_factories_ =
parent_.factory_.createListenerFilterFactoryList(config.listener_filters(), *this);
}
// Add original dst listener filter if 'use_original_dst' flag is set.
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.

Per my comment in the data-plane-api repo, can we deprecate the use_original_dst field in DEPRECATED.md and docs, and push people towards using the filter directly.

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.

Done.

// is implemented, this needs to be run after the filter chain has been
// selected.
if (PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.filter_chains()[0], use_proxy_proto, false)) {
auto& factory =
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'm wondering if we should even register proxy proto as a factory, given that in the future we aren't going to use it as a listener filter. I don't think it's a big deal either way, but just throwing it out there for thoughts.

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.

IMO, I would leave the door open to use it as a listener filter as well, in case someone must do filter chain matching after proxy protocol has restored the destination address.

@jrajahalme
Copy link
Copy Markdown
Contributor Author

@mattklein123 Thanks for your thorough review! I'll post commits addressing your comments right after the test run I'm doing locally finishes.

@jrajahalme
Copy link
Copy Markdown
Contributor Author

Will also merge master to resolve the conflict.

Deprecate 'use_proxy_protocol' boolean from the v2 LDS API, as the
corresponding functionality can be attained with listener filters and
filter chain matching.

Handing off from one listener to another is supported for v2 API only
until 'use_proxy_protocol' flag is removed. After that v2 API users
have to use filter chain matching to implement filter chain selection.

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
@jrajahalme
Copy link
Copy Markdown
Contributor Author

Don't have the time to wait for the test run locally, hoping this tests OK.

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

LGTM, a few small comments. Please merge master in with the real data-plane-api change.


Address::InstanceConstSharedPtr local_address_;
ListenerCallbacks& cb_;
bool hand_off_restored_destinations_;
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.

const

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.

I have to learn this someday :-) Btw. this factors in to the discussion about this being plural or not in the other comment..

/**
* @return bool if a connection should be handed off to another Listener after the original
* destination address has been restored. 'true' when 'use_original_dst' flag in listener
* configuration is set, false otherwise. Note that this flag will be removed from the v2
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 explicitly use the word "deprecated" in here somewhere so that when we search for deprecated things this comes up?

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.

Done.

* configuration is set, false otherwise. Note that this flag will be removed from the v2
* API.
*/
virtual bool handOffRestoredDestinations() const PURE;
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.

Should this be not plural? handOffRestoredDestination() ? And same with all variables similarly named?

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.

A listener accepts many connections, each of which has a destination address, and the listener will either hand all restored destinations off to another listener (if found) or not. To me this calls for a plural, but I'm happy to change it you don't buy this line of reasoning.

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.

OK makes sense. I guess I would probably name it handOffRestoredDestinationConnections(), but I don't feel that strongly about it.

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.

OK, I'll change this, hold on for a while :-)

Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
…nections().

Remame handOffRestoredDestinations() as
handOffRestoredDestinationConnections(). Corresponding rename for
parameter and member variable names, too.

Constify the 'bool hand_off_restored_destination_connections_' member
variable in tests.

Suggested-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Awesome work. Thank you!

@mattklein123 mattklein123 merged commit eb02089 into envoyproxy:master Jan 23, 2018
@jrajahalme
Copy link
Copy Markdown
Contributor Author

I've been running the starting point of this PR for a couple of months now, but still positively surprised by the code quality & readability increase during the review process! Thanks for keeping a to it for the last two weeks!

@mattklein123
Copy link
Copy Markdown
Member

I've been running the starting point of this PR for a couple of months now, but still positively surprised by the code quality & readability increase during the review process! Thanks for keeping a to it for the last two weeks!

Thank you for being a good sport! :)

jrajahalme added a commit to jrajahalme/envoy that referenced this pull request Feb 9, 2018
We should not have default parameter values on virtual functions, but
this one slipped through.

Fixes: eb02089 ("Listener: Add listener filters. (envoyproxy#2346)")
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
mattklein123 pushed a commit that referenced this pull request Feb 9, 2018
…2573)

We should not have default parameter values on virtual functions, but
this one slipped through.

Fixes: eb02089 ("Listener: Add listener filters. (#2346)")
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Shikugawa pushed a commit to Shikugawa/envoy that referenced this pull request Mar 28, 2020
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
jpsim added a commit that referenced this pull request Nov 28, 2022
To pull in bazelbuild/rules_apple#1488, which should fix our CocoaPods integration and allow us to re-add it.

Risk Level: Medium for iOS users who use the xcframework, low for everyone else
Testing: There's a recent CI job that validates SwiftPM integration that acts as a good integration test for this
Docs Changes: None for now, this isn't really a user-facing change, as Xcode/SwiftPM handles both the old and new xcframework format/layout transparently
Release Notes: None for now, this isn't really a user-facing change

Signed-off-by: JP Simard <jp@jpsim.com>
jpsim added a commit that referenced this pull request Nov 29, 2022
To pull in bazelbuild/rules_apple#1488, which should fix our CocoaPods integration and allow us to re-add it.

Risk Level: Medium for iOS users who use the xcframework, low for everyone else
Testing: There's a recent CI job that validates SwiftPM integration that acts as a good integration test for this
Docs Changes: None for now, this isn't really a user-facing change, as Xcode/SwiftPM handles both the old and new xcframework format/layout transparently
Release Notes: None for now, this isn't really a user-facing change

Signed-off-by: JP Simard <jp@jpsim.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.

7 participants