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

Listen on multiple addresses for net_plugin p2p. #1411

Merged
merged 13 commits into from
Jul 25, 2023

Conversation

jgiszczak
Copy link
Contributor

@jgiszczak jgiszczak commented Jul 15, 2023

This PR allows net_plugin to listen on multiple address:port pairs.

--p2p-listen-endpoint may now be specified multiple times. Duplicates are ignored.
--p2p-server-address may now be specified multiple times. It may be specified no more times than the number of p2p listen endpoints. Each p2p listen endpoint will be assigned a p2p-server-address in order until the list is exhausted. Listen endpoints with no corresponding p2p-server-address will use their listen address and port as usual. For outgoing connections, the first p2p-server-address will be used as the peer address in handshakes. If not specified, the first listen endpoint will be used.

This feature enables differing firewall rules per port, allowing the ability to distinguish between internal cluster peers, other producer peers, and general public peers, as well as any other categories which may be useful.

Documentation Updates

This PR adds the following fields to the results of the connections API in net_api_plugin:

  • remote_ip
  • remote_port
  • is_socket_open
  • is_blocks_only
  • is_transactions_only

The first two are strings. The rest are boolean values.

@jgiszczak jgiszczak requested review from dimas1185 and heifner July 17, 2023 16:11
@jgiszczak jgiszczak marked this pull request as ready for review July 17, 2023 16:12
Copy link
Member

@spoonincode spoonincode left a comment

Choose a reason for hiding this comment

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

This change prevents disabling p2p listen endpoint, is there some way we can maintain that ability?

plugins/net_plugin/net_plugin.cpp Outdated Show resolved Hide resolved
plugins/net_plugin/net_plugin.cpp Outdated Show resolved Hide resolved
p2p_address = options.at( "p2p-listen-endpoint" ).as<string>();
EOS_ASSERT( p2p_address.length() <= max_p2p_address_length, chain::plugin_config_exception,
"p2p-listen-endpoint too long, must be less than ${m}", ("m", max_p2p_address_length) );
if( options.count( "p2p-listen-endpoint" ) && !options.at("p2p-listen-endpoint").as<vector<string>>().empty() && options.at("p2p-listen-endpoint").as<vector<string>>()[0].length()) {
Copy link
Member

Choose a reason for hiding this comment

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

I thinks && !options.at("p2p-listen-endpoint").as<vector<string>>()[0].empty() is easier to understand.

Copy link
Contributor

@dimas1185 dimas1185 Jul 19, 2023

Choose a reason for hiding this comment

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

I think we can remove vector checks at all. code below should perfectly handle empty vector. Or you can add a check later if vector is empty - looks more succinct, easier to understand and more optimal since you do not construct vector multiple times

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'd like to retain the checks in case the default value is ever removed. I figured it was ok to reconstruct the vector because this is startup code executed only once and it would be very unusual for the vector size to exceed even 10 elements.

Copy link
Contributor

@dimas1185 dimas1185 Jul 21, 2023

Choose a reason for hiding this comment

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

my main point was having concise and easy to read code at first. I agree that performance could be neglected here if it adds readability or simplicity.
So if you remove it or at least split that huge if statement - that will improve readability.
technically I do not see any difference in functionality if you'll leave it like that:

if( options.count( "p2p-listen-endpoint" ) ) {
}

in that case p2p_addresses will be empty anyways and sort /erase won't crash on empty vector. If I missed something you could just split the if like that:

if( options.count( "p2p-listen-endpoint" ) ) {
   auto p2ps = options.at( "p2p-listen-endpoint" ).as<vector<string>>();
   if (!p2ps.empty() && !p2ps.front().empty()) { 
      p2p_addresses = p2ps;
       /*...*/
   }
}

I'm not hard on this, just trying to keep code reasonably simple. net_plugin code is complicated enough already.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated for readability.

plugins/net_plugin/net_plugin.cpp Outdated Show resolved Hide resolved
plugins/net_plugin/net_plugin.cpp Outdated Show resolved Hide resolved
plugins/net_plugin/net_plugin.cpp Outdated Show resolved Hide resolved

if( !p2p_address.empty() ) {
auto [host, port] = fc::split_host_port(listen_address);
std::transform(p2p_addresses.begin(), p2p_addresses.end(), p2p_server_addresses.begin(),
Copy link
Member

Choose a reason for hiding this comment

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

I know you do a resize above, but an assert that these are the same size would be good.

Copy link
Contributor

Choose a reason for hiding this comment

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

  • it looks better to move line 3991 just above that one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added assert.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dimas1185 I'm sorry, the line numbers have moved around too much. I'm not sure what you mean.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jgiszczak you can skip it. assert looks good.
I meant this one:

`p2p_server_addresses.resize(p2p_addresses.size()); // extend with empty entries as needed`

plugins/net_plugin/net_plugin.cpp Outdated Show resolved Hide resolved
Outbound connections are always attributed to the first listen address.
Copy link
Contributor

@dimas1185 dimas1185 left a comment

Choose a reason for hiding this comment

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

please add unit and/or integration test where you check behavior for multiple endpoints specified

Erase undefined elements from p2p_addresses vector after std::unique().
Add assert before std::transform of two vectors.
Const correctness and whitespace cleanup.
@heifner heifner added the OCI Work exclusive to OCI team label Jul 20, 2023
@@ -182,7 +182,7 @@ class bp_connection_manager {

fc_dlog(self()->get_logger(), "pending_downstream_neighbors: ${pending_downstream_neighbors}",
("pending_downstream_neighbors", to_string(pending_downstream_neighbors)));
for (auto neighbor : pending_downstream_neighbors) { self()->connections.connect(config.bp_peer_addresses[neighbor]); }
for (auto neighbor : pending_downstream_neighbors) { self()->connections.connect(config.bp_peer_addresses[neighbor], *self()->p2p_addresses.begin() ); }
Copy link
Member

Choose a reason for hiding this comment

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

As discussed please update help and PR description indicating that the first configured server_address is reported in the handshake message to peers. Also guard against p2p_addresses being empty here.

@spoonincode spoonincode dismissed their stale review July 20, 2023 18:38

my concern resolved

@@ -0,0 +1,75 @@
#!/usr/bin/env python3
Copy link
Contributor

Choose a reason for hiding this comment

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

thanks for adding the test.
It is a bit confusing, can you add more comments about its actions?

also, now net_plugin's options p2p-listen-endpoint and p2p-server-address could be a vector. So I think we should have a test where you specify multiple entries and ensure those are used appropriately.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comments added and text expanded to multiple ports and to test the --p2p-server-address parameter better as well.

Exercise multiple listen endpoints, with overrides, in p2p test.
Add network topology diagrams to p2p_multiple_listen_test.
@jgiszczak jgiszczak merged commit 172eb8d into main Jul 25, 2023
@jgiszczak jgiszczak deleted the p2p-multiple-listen-addresses branch July 25, 2023 16:12
@BenjaminGormanPMP
Copy link

[Group: "P2P Enhancements"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OCI Work exclusive to OCI team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow use of multiple ports for P2P
5 participants