From 9dcf939af640b50ea590b1735bf4a9a4eb2867ff Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 23 Jan 2026 17:36:35 -0800 Subject: [PATCH 1/3] [WIP] Tmp code to verify xDS HTTP Connect end-to-end allows nested transport_sockets = RawBuffer --- .../main/java/io/grpc/xds/MessagePrinter.java | 10 +++- .../java/io/grpc/xds/XdsClusterResource.java | 20 +++++--- .../grpc/xds/GrpcXdsClientImplDataTest.java | 46 +++++++++++++++++++ xds/third_party/envoy/import.sh | 1 + .../raw_buffer/v3/raw_buffer.proto | 21 +++++++++ 5 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 xds/third_party/envoy/src/main/proto/envoy/extensions/transport_sockets/raw_buffer/v3/raw_buffer.proto diff --git a/xds/src/main/java/io/grpc/xds/MessagePrinter.java b/xds/src/main/java/io/grpc/xds/MessagePrinter.java index d6fdaa81dd7..91db3c6f1f8 100644 --- a/xds/src/main/java/io/grpc/xds/MessagePrinter.java +++ b/xds/src/main/java/io/grpc/xds/MessagePrinter.java @@ -35,6 +35,8 @@ import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; import io.envoyproxy.envoy.extensions.load_balancing_policies.round_robin.v3.RoundRobin; import io.envoyproxy.envoy.extensions.load_balancing_policies.wrr_locality.v3.WrrLocality; +import io.envoyproxy.envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport; +import io.envoyproxy.envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext; import io.envoyproxy.envoy.service.discovery.v3.Resource; @@ -72,8 +74,12 @@ private static JsonFormat.Printer newPrinter() { .add(ClusterConfig.getDescriptor()) .add(ClusterLoadAssignment.getDescriptor()) .add(WrrLocality.getDescriptor()) - .add(TypedStruct.getDescriptor()) - .add(RoundRobin.getDescriptor()); + .add(RoundRobin.getDescriptor()) + // Transports + .add(Http11ProxyUpstreamTransport.getDescriptor()) + .add(RawBuffer.getDescriptor()) + // Always last, guarding the semicolon. + .add(TypedStruct.getDescriptor()); try { @SuppressWarnings("unchecked") Class routeLookupClusterSpecifierClass = diff --git a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java index d9848d97017..147dbff11db 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java @@ -83,6 +83,8 @@ class XdsClusterResource extends XdsResourceType { static final String TRANSPORT_SOCKET_NAME_HTTP11_PROXY = "type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3" + ".Http11ProxyUpstreamTransport"; + static final String TRANSPORT_SOCKET_NAME_RAW_BUFFER = + "type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer"; private final LoadBalancerRegistry loadBalancerRegistry = LoadBalancerRegistry.getDefaultRegistry(); @@ -260,15 +262,21 @@ private static StructOrError parseNonAggregateCluster( boolean hasTransportSocket = cluster.hasTransportSocket(); TransportSocket transportSocket = cluster.getTransportSocket(); - if (hasTransportSocket && !TRANSPORT_SOCKET_NAME_TLS.equals(transportSocket.getName()) - && !(isEnabledXdsHttpConnect - && TRANSPORT_SOCKET_NAME_HTTP11_PROXY.equals(transportSocket.getName()))) { + + String transportSocketName = hasTransportSocket ? transportSocket.getName() : ""; + boolean socketIsTls = transportSocketName.equals(TRANSPORT_SOCKET_NAME_TLS); + boolean socketIsH1Proxy = transportSocketName.equals(TRANSPORT_SOCKET_NAME_HTTP11_PROXY); + boolean supportSocketIsH1Proxy = isEnabledXdsHttpConnect && socketIsH1Proxy; + + if (hasTransportSocket && !socketIsTls && !supportSocketIsH1Proxy) { return StructOrError.fromError( - "transport-socket with name " + transportSocket.getName() + " not supported."); + "transport-socket with name " + transportSocketName + " not supported, socketIsTls=" + + socketIsTls + ", socketIsH1Proxy=" + socketIsH1Proxy + + ", isEnabledXdsHttpConnect=" + isEnabledXdsHttpConnect + + ", supportSocketIsH1Proxy=" + supportSocketIsH1Proxy + "."); } - if (hasTransportSocket && isEnabledXdsHttpConnect - && TRANSPORT_SOCKET_NAME_HTTP11_PROXY.equals(transportSocket.getName())) { + if (hasTransportSocket && supportSocketIsH1Proxy) { isHttp11ProxyAvailable = true; try { Http11ProxyUpstreamTransport wrappedTransportSocket = transportSocket diff --git a/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java b/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java index be29e5e719f..849cee8a108 100644 --- a/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java +++ b/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static io.envoyproxy.envoy.config.route.v3.RouteAction.ClusterSpecifierCase.CLUSTER_SPECIFIER_PLUGIN; import static io.grpc.xds.XdsClusterResource.TRANSPORT_SOCKET_NAME_HTTP11_PROXY; +import static io.grpc.xds.XdsClusterResource.TRANSPORT_SOCKET_NAME_RAW_BUFFER; import static io.grpc.xds.XdsEndpointResource.GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; @@ -97,6 +98,7 @@ import io.envoyproxy.envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin; import io.envoyproxy.envoy.extensions.load_balancing_policies.wrr_locality.v3.WrrLocality; import io.envoyproxy.envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport; +import io.envoyproxy.envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateProviderPluginInstance; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; @@ -2639,6 +2641,50 @@ public void parseNonAggregateCluster_withHttp11ProxyTransportSocket() throws Exc assertThat(result.isHttp11ProxyAvailable()).isTrue(); } + /** + * Http11ProxyUpstreamTransport with transport_socket=RawBuffer must behave the same as + * when transport_socket is unset. + */ + @Test + public void parseNonAggregateCluster_withHttp11ProxyTransportSocket_rawBuffer() throws Exception { + XdsClusterResource.isEnabledXdsHttpConnect = true; + + // Nested transport_socket (Http11ProxyUpstreamTransport.transport_socket). + TransportSocket transportSocketRawBuffer = TransportSocket.newBuilder() + .setName(TRANSPORT_SOCKET_NAME_RAW_BUFFER) + .setTypedConfig(Any.pack(RawBuffer.getDefaultInstance())) + .build(); + + Http11ProxyUpstreamTransport http11ProxyUpstreamTransport = + Http11ProxyUpstreamTransport.newBuilder() + .setTransportSocket(transportSocketRawBuffer) + .build(); + + TransportSocket transportSocket = TransportSocket.newBuilder() + .setName(TRANSPORT_SOCKET_NAME_HTTP11_PROXY) + .setTypedConfig(Any.pack(http11ProxyUpstreamTransport)) + .build(); + + Cluster cluster = Cluster.newBuilder() + .setName("cluster-http11-proxy.googleapis.com") + .setType(DiscoveryType.EDS) + .setEdsClusterConfig( + EdsClusterConfig.newBuilder() + .setEdsConfig( + ConfigSource.newBuilder().setAds(AggregatedConfigSource.getDefaultInstance())) + .setServiceName("service-http11-proxy.googleapis.com")) + .setLbPolicy(LbPolicy.ROUND_ROBIN) + .setTransportSocket(transportSocket) + .build(); + + CdsUpdate result = + XdsClusterResource.processCluster(cluster, null, LRS_SERVER_INFO, + LoadBalancerRegistry.getDefaultRegistry()); + + assertThat(result).isNotNull(); + assertThat(result.isHttp11ProxyAvailable()).isTrue(); + } + @Test public void processCluster_parsesOrcaLrsPropagationMetrics() throws ResourceInvalidException { LoadStatsManager2.isEnabledOrcaLrsPropagation = true; diff --git a/xds/third_party/envoy/import.sh b/xds/third_party/envoy/import.sh index 0ad90f7baf0..152900cbf90 100755 --- a/xds/third_party/envoy/import.sh +++ b/xds/third_party/envoy/import.sh @@ -96,6 +96,7 @@ envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.proto envoy/extensions/load_balancing_policies/round_robin/v3/round_robin.proto envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto envoy/extensions/transport_sockets/http_11_proxy/v3/upstream_http_11_connect.proto +envoy/extensions/transport_sockets/raw_buffer/v3/raw_buffer.proto envoy/extensions/transport_sockets/tls/v3/cert.proto envoy/extensions/transport_sockets/tls/v3/common.proto envoy/extensions/transport_sockets/tls/v3/secret.proto diff --git a/xds/third_party/envoy/src/main/proto/envoy/extensions/transport_sockets/raw_buffer/v3/raw_buffer.proto b/xds/third_party/envoy/src/main/proto/envoy/extensions/transport_sockets/raw_buffer/v3/raw_buffer.proto new file mode 100644 index 00000000000..4d6436f2a78 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/extensions/transport_sockets/raw_buffer/v3/raw_buffer.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package envoy.extensions.transport_sockets.raw_buffer.v3; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.transport_sockets.raw_buffer.v3"; +option java_outer_classname = "RawBufferProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/raw_buffer/v3;raw_bufferv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Raw Buffer] +// [#extension: envoy.transport_sockets.raw_buffer] + +// Configuration for raw buffer transport socket. +message RawBuffer { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.transport_socket.raw_buffer.v2.RawBuffer"; +} From 582c6baace0a60c16167f19a2a61b73861a8835e Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 23 Jan 2026 17:44:43 -0800 Subject: [PATCH 2/3] fix warnings --- .../java/io/grpc/xds/XdsClusterResource.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java index 147dbff11db..ea3b7d5abfa 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java @@ -40,6 +40,7 @@ import io.envoyproxy.envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; +import io.grpc.InternalLogId; import io.grpc.LoadBalancerRegistry; import io.grpc.NameResolver; import io.grpc.internal.GrpcUtil; @@ -50,6 +51,8 @@ import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.client.BackendMetricPropagation; import io.grpc.xds.client.XdsClient.ResourceUpdate; +import io.grpc.xds.client.XdsLogger; +import io.grpc.xds.client.XdsLogger.XdsLogLevel; import io.grpc.xds.client.XdsResourceType; import io.grpc.xds.internal.security.CommonTlsContextUtil; import java.util.List; @@ -87,6 +90,8 @@ class XdsClusterResource extends XdsResourceType { "type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer"; private final LoadBalancerRegistry loadBalancerRegistry = LoadBalancerRegistry.getDefaultRegistry(); + private static final XdsLogger logger = XdsLogger.withLogId( + InternalLogId.allocate("xds-cluster-resource", "sergiitk")); private static final XdsClusterResource instance = new XdsClusterResource(); @@ -266,17 +271,23 @@ private static StructOrError parseNonAggregateCluster( String transportSocketName = hasTransportSocket ? transportSocket.getName() : ""; boolean socketIsTls = transportSocketName.equals(TRANSPORT_SOCKET_NAME_TLS); boolean socketIsH1Proxy = transportSocketName.equals(TRANSPORT_SOCKET_NAME_HTTP11_PROXY); - boolean supportSocketIsH1Proxy = isEnabledXdsHttpConnect && socketIsH1Proxy; + boolean socketIsH1ProxyAndSupported = isEnabledXdsHttpConnect && socketIsH1Proxy; - if (hasTransportSocket && !socketIsTls && !supportSocketIsH1Proxy) { - return StructOrError.fromError( - "transport-socket with name " + transportSocketName + " not supported, socketIsTls=" - + socketIsTls + ", socketIsH1Proxy=" + socketIsH1Proxy - + ", isEnabledXdsHttpConnect=" + isEnabledXdsHttpConnect - + ", supportSocketIsH1Proxy=" + supportSocketIsH1Proxy + "."); + if (hasTransportSocket && !(socketIsTls || socketIsH1ProxyAndSupported)) { + String errMsg = "transport-socket with name " + transportSocketName + " not supported"; + + @SuppressWarnings("AlreadyChecked") // todo remove + String extraErrorMsg = errMsg + + ", socketIsTls=" + socketIsTls + + ", socketIsH1Proxy=" + socketIsH1Proxy + + ", isEnabledXdsHttpConnect=" + isEnabledXdsHttpConnect + + ", socketIsH1ProxyAndSupported=" + socketIsH1ProxyAndSupported + "."; + logger.log(XdsLogLevel.ERROR, extraErrorMsg); + + return StructOrError.fromError(errMsg + "."); } - if (hasTransportSocket && supportSocketIsH1Proxy) { + if (hasTransportSocket && socketIsH1ProxyAndSupported) { isHttp11ProxyAvailable = true; try { Http11ProxyUpstreamTransport wrappedTransportSocket = transportSocket From dc66629f72b05e7b896e9a90e2695d3db4a5792d Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Mon, 26 Jan 2026 12:26:22 -0800 Subject: [PATCH 3/3] h11 proxy parsing bug: check for name, not type --- .../java/io/grpc/xds/XdsClusterResource.java | 35 ++++++++++++++----- .../xds/ClusterResolverLoadBalancerTest.java | 6 ++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java index ea3b7d5abfa..8600ff25bbc 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java @@ -83,11 +83,20 @@ class XdsClusterResource extends XdsResourceType { "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext"; private static final String TYPE_URL_UPSTREAM_TLS_CONTEXT_V2 = "type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext"; - static final String TRANSPORT_SOCKET_NAME_HTTP11_PROXY = - "type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3" - + ".Http11ProxyUpstreamTransport"; - static final String TRANSPORT_SOCKET_NAME_RAW_BUFFER = - "type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer"; + + // TODO(sergiitk): should this be in XdsResourceType next to TRANSPORT_SOCKET_NAME_TLS? + @VisibleForTesting + static final String TRANSPORT_SOCKET_NAME_HTTP11_PROXY = "envoy.transport_sockets.http_11_proxy"; + @VisibleForTesting + static final String TRANSPORT_SOCKET_NAME_RAW_BUFFER = "envoy.transport_sockets.raw_buffer"; + + // TODO(sergiitk): tell Eric about the bug. + // static final String TRANSPORT_SOCKET_NAME_HTTP11_PROXY = + // "type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3" + // + ".Http11ProxyUpstreamTransport"; + // static final String TRANSPORT_SOCKET_NAME_RAW_BUFFER = + // "type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer"; + private final LoadBalancerRegistry loadBalancerRegistry = LoadBalancerRegistry.getDefaultRegistry(); private static final XdsLogger logger = XdsLogger.withLogId( @@ -282,19 +291,29 @@ private static StructOrError parseNonAggregateCluster( + ", socketIsH1Proxy=" + socketIsH1Proxy + ", isEnabledXdsHttpConnect=" + isEnabledXdsHttpConnect + ", socketIsH1ProxyAndSupported=" + socketIsH1ProxyAndSupported + "."; - logger.log(XdsLogLevel.ERROR, extraErrorMsg); + logger.log(XdsLogLevel.FORCE_WARNING, extraErrorMsg); return StructOrError.fromError(errMsg + "."); } if (hasTransportSocket && socketIsH1ProxyAndSupported) { + logger.log(XdsLogLevel.FORCE_INFO, "Enabling HTTP11 Proxy, trying to parse"); isHttp11ProxyAvailable = true; + try { Http11ProxyUpstreamTransport wrappedTransportSocket = transportSocket - .getTypedConfig().unpack(io.envoyproxy.envoy.extensions.transport_sockets - .http_11_proxy.v3.Http11ProxyUpstreamTransport.class); + .getTypedConfig().unpack(Http11ProxyUpstreamTransport.class); + hasTransportSocket = wrappedTransportSocket.hasTransportSocket(); transportSocket = wrappedTransportSocket.getTransportSocket(); + transportSocketName = hasTransportSocket ? transportSocket.getName() : ""; + + logger.log(XdsLogLevel.FORCE_INFO, + "Enabled HTTP11 Proxy, wrapped socket: " + transportSocketName + ); + + // TODO(sergiitk): tell Eric this is missing the wrapped socket check. + } catch (InvalidProtocolBufferException e) { return StructOrError.fromError( "Cluster " + clusterName + ": malformed Http11ProxyUpstreamTransport: " + e); diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index 5e524f79596..e002407163f 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -416,8 +416,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { XdsClusterResource.isEnabledXdsHttpConnect = true; Cluster cluster = EDS_CLUSTER.toBuilder() .setTransportSocket(TransportSocket.newBuilder() - .setName( - "type.googleapis.com/" + Http11ProxyUpstreamTransport.getDescriptor().getFullName()) + .setName("envoy.transport_sockets.http_11_proxy") .setTypedConfig(Any.pack(Http11ProxyUpstreamTransport.getDefaultInstance()))) .build(); // Proxy address in endpointMetadata, and no proxy in locality metadata @@ -466,8 +465,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { XdsClusterResource.isEnabledXdsHttpConnect = true; Cluster cluster = EDS_CLUSTER.toBuilder() .setTransportSocket(TransportSocket.newBuilder() - .setName( - "type.googleapis.com/" + Http11ProxyUpstreamTransport.getDescriptor().getFullName()) + .setName("envoy.transport_sockets.http_11_proxy") .setTypedConfig(Any.pack(Http11ProxyUpstreamTransport.getDefaultInstance()))) .build(); // No proxy address in endpointMetadata, and proxy in locality metadata