Skip to content

Conversation

@shivaspeaks
Copy link
Member

Fixes #11737

@shivaspeaks shivaspeaks changed the title Listener type validation xds: listener type validation Mar 3, 2025
@shivaspeaks shivaspeaks requested a review from ejona86 March 3, 2025 15:25
@ejona86 ejona86 self-requested a review March 5, 2025 21:20
Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

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

Sorry, I didn't mean to approve

@shivaspeaks shivaspeaks added the kokoro:run Add this label to a PR to tell Kokoro the code is safe and tests can be run label Mar 6, 2025
@grpc-kokoro grpc-kokoro removed the kokoro:run Add this label to a PR to tell Kokoro the code is safe and tests can be run label Mar 6, 2025
@shivaspeaks shivaspeaks requested a review from ejona86 March 6, 2025 20:52
}
StatusException statusException = Status.UNAVAILABLE.withDescription(
String.format("Listener %s unavailable, xDS node ID: %s", resourceName,
String.format("%s listener unavailable, xDS node ID: %s", resourceName,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: what would be the reason to switch the order of the error format here? I think Listener %s is slightly more common in the code base. Consistent formatting helps with searching when debugging issues.

Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

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

I found these comments laying around. I don't know why I didn't send it out earlier.

@shivaspeaks shivaspeaks requested a review from ejona86 March 18, 2025 17:03
@shivaspeaks shivaspeaks requested a review from ejona86 March 19, 2025 18:07
@larry-safran
Copy link
Contributor

While it is in the gRFC, why is it really important to enforce a returned address being non-null? This doesn't seem to really provide value as the address was already known for communicating to the xds server in the first place.

@ejona86
Copy link
Member

ejona86 commented Mar 24, 2025

This doesn't seem to really provide value as the address was already known for communicating to the xds server in the first place.

The returned Listener address tells the server what to listen on. We didn't remove it. We just made it so that the control plane can have a trivial job of filling in the correct value.

Copy link
Contributor

@kannanjgithub kannanjgithub left a comment

Choose a reason for hiding this comment

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

Review comments.

SocketAddress socketAddress = proto.getAddress().getSocketAddress();
socketAddress = proto.getAddress().getSocketAddress();
address = socketAddress.getAddress();
if (address.isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add unit test in GrpcXdsClientImplDataTest.

case NAMED_PORT:
address = address + ":" + socketAddress.getNamedPort();
break;
throw new ResourceInvalidException("NAMED_PORT is not supported in gRPC.");
Copy link
Contributor

Choose a reason for hiding this comment

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

Add unit test in GrpcXdsClientImplDataTest.

// Process Route
XdsConfig update = updateOrStatus.getValue();
HttpConnectionManager httpConnectionManager = update.getListener().httpConnectionManager();
if (httpConnectionManager == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add unit test for when the listener update is missing httpConnectionManager.

}
logger.log(Level.FINEST, "Received Lds update {0}", update);
checkNotNull(update.listener(), "update");
if (update.listener() == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add unit test for this case as well.

XdsConfig update = updateOrStatus.getValue();
HttpConnectionManager httpConnectionManager = update.getListener().httpConnectionManager();
if (httpConnectionManager == null) {
String error = "API Listener: httpConnectionManager does not exist.";
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: this error string is never reused, thus no need to store it in a local variable.
We can simply rewrite as
logger.log(XdsLogLevel.INFO, "API Listener: httpConnectionManager does not exist.");

Comment on lines +459 to +462
if (!ldsAddressHnP.hasPort() || !listenerAddressHnP.hasPort()
|| ldsAddressHnP.getPort() != listenerAddressHnP.getPort()) {
return false;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we have a unit test for this if block?

Copy link
Contributor

Choose a reason for hiding this comment

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

The tests test hostname mismatch and port mismatch but not missing host or missing port. Like "127.0.0.0" or ":8080"

"filter-chain-bar", defaultFilterChainMatch, httpConnectionManager,
tlsContextForDefaultFilterChain, tlsContextManager);
EnvoyServerProtoData.Listener listener = EnvoyServerProtoData.Listener.create(
return Listener.create(
Copy link
Contributor

Choose a reason for hiding this comment

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

Previously was better?

Listener.create("listener", "20.3.4.5:1",
ImmutableList.copyOf(Collections.singletonList(filterChain)), null, Protocol.TCP));
xdsClient.deliverLdsUpdate(listenerUpdate);
verify(listener, timeout(10000)).onNotServing(any());
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

@kannanjgithub kannanjgithub left a comment

Choose a reason for hiding this comment

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

Review comments.

mock(TlsContextManager.class));
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(
Listener.create("listener", "20.3.4.5:1",
Listener.create("listener", "20.3.4.5:",
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it work if you commit the trailing ':' ?
Does the InetAddress parsing work for an address with just the :8080 missing the hostname part?

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it work if you commit the trailing ':' ?

For this test case, NO because even if I give same port it will fail at hostname matching, ldsHostname(20.3.4.5) is not same as listenerAddressHostname(10.1.2.3).

Does the InetAddress parsing work for an address with just the :8080 missing the hostname part?

No it doesn't work without hostname. It fails when we convert to InetAddress using InetAddresses.forString("") using empty string as hostname.

InetAddress listenerIp = InetAddresses.forString(listenerAddressHnP.getHost());
InetAddress ldsIp = InetAddresses.forString(ldsAddressHnP.getHost());
return listenerIp.equals(ldsIp);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you get problems with the previous way?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, there were no problems here but I think if port isn't available or ports are not same then there's no point of parsing HostAndPort into InetAddress

Copy link
Contributor

@kannanjgithub kannanjgithub left a comment

Choose a reason for hiding this comment

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

Clarification questions

Copy link
Contributor

@kannanjgithub kannanjgithub left a comment

Choose a reason for hiding this comment

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

Question.

@shivaspeaks shivaspeaks merged commit c8d1e6e into grpc:master Apr 3, 2025
16 checks passed
@shivaspeaks shivaspeaks deleted the listener-type-validation branch April 3, 2025 05:52
Copy link
Collaborator

@danielzhaotongliu danielzhaotongliu left a comment

Choose a reason for hiding this comment

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

LGTM.

/**
* Returns the least-specific match-all Filter Chain Match.
*/
private static FilterChainMatch createMatch() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: what would be the reason for increasing this visibility of this method (and createTls()), I don't seee them being referenced in other test files? Perhaps I am missing something.

Generally, it is good practice to keep the visibility of members as inaccessible (lowest visibility) as possible.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 3, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XdsNameResolver and XdsServerWrapper don't check listener type

6 participants