Merge branch 'non_per_call_metrics_wrr' into non_per_call_metrics_pf

pull/35984/head
Mark D. Roth 1 year ago
commit 239009cc81
  1. 1
      BUILD
  2. 76
      CMakeLists.txt
  3. 24
      bazel/experiments.bzl
  4. 154
      build_autogenerated.yaml
  5. 2
      doc/python/sphinx/grpc_observability.rst
  6. 1
      doc/python/sphinx/index.rst
  7. 2
      grpc.gyp
  8. 8
      requirements.bazel.txt
  9. 1
      src/core/ext/filters/channel_idle/channel_idle_filter.cc
  10. 2
      src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc
  11. 2
      src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc
  12. 38
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  13. 23
      src/core/ext/transport/chttp2/transport/context_list_entry.h
  14. 4
      src/core/ext/transport/chttp2/transport/internal.h
  15. 36
      src/core/ext/transport/chttp2/transport/writing.cc
  16. 43
      src/core/ext/xds/xds_client_grpc.cc
  17. 13
      src/core/ext/xds/xds_client_grpc.h
  18. 4
      src/core/ext/xds/xds_server_config_fetcher.cc
  19. 8
      src/core/lib/channel/promise_based_filter.h
  20. 1
      src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc
  21. 2
      src/core/lib/experiments/config.cc
  22. 2
      src/core/lib/experiments/experiments.cc
  23. 3
      src/core/lib/experiments/experiments.h
  24. 7
      src/core/lib/experiments/rollouts.yaml
  25. 3
      src/core/lib/resource_quota/arena.h
  26. 27
      src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc
  27. 39
      src/core/lib/surface/call.cc
  28. 8
      src/core/lib/surface/init.cc
  29. 3
      src/core/resolver/xds/xds_resolver.cc
  30. 9
      src/core/tsi/ssl_transport_security.cc
  31. 70
      src/core/tsi/ssl_transport_security_utils.cc
  32. 18
      src/core/tsi/ssl_transport_security_utils.h
  33. 54
      src/python/grpcio/grpc/_observability.py
  34. 2
      src/python/grpcio/grpc/aio/_interceptor.py
  35. 2
      src/python/grpcio_observability/README.rst
  36. 2
      test/core/security/BUILD
  37. 67
      test/core/security/grpc_tls_crl_provider_test.cc
  38. 11
      test/core/tsi/BUILD
  39. 208
      test/core/tsi/ssl_transport_security_utils_test.cc
  40. 1
      test/core/tsi/test_creds/crl_data/BUILD
  41. 5
      test/core/tsi/test_creds/crl_data/README
  42. 2
      test/core/tsi/test_creds/crl_data/crls/BUILD
  43. 15
      test/core/tsi/test_creds/crl_data/crls/invalid_content.crl
  44. 15
      test/core/tsi/test_creds/crl_data/crls/invalid_signature.crl
  45. 28
      test/core/tsi/test_creds/crl_data/evil_ca.key
  46. 21
      test/core/tsi/test_creds/crl_data/evil_ca.pem
  47. 18
      test/core/tsi/test_creds/crl_data/evil_ca_gen.sh
  48. 2
      test/core/tsi/test_creds/crl_data/intermediate_gen.sh
  49. 24
      test/core/tsi/transport_security_test_lib.cc
  50. 8
      test/core/tsi/transport_security_test_lib.h
  51. 2
      test/core/util/BUILD
  52. 525
      test/core/util/passthru_endpoint.cc
  53. 58
      test/core/util/passthru_endpoint.h
  54. 132
      test/cpp/end2end/xds/xds_core_end2end_test.cc
  55. 79
      test/cpp/end2end/xds/xds_csds_end2end_test.cc
  56. 11
      test/cpp/end2end/xds/xds_end2end_test_lib.cc
  57. 7
      test/cpp/end2end/xds/xds_wrr_end2end_test.cc
  58. 18
      test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
  59. 6
      test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
  60. 55
      test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
  61. 41
      test/cpp/microbenchmarks/fullstack_fixtures.h

@ -3880,6 +3880,7 @@ grpc_cc_library(
external_deps = [
"absl/base:core_headers",
"absl/status",
"absl/status:statusor",
"absl/strings",
"libcrypto",
"libssl",

76
CMakeLists.txt generated

@ -3942,7 +3942,6 @@ add_library(benchmark_helpers ${_gRPC_STATIC_WIN32}
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -4715,7 +4714,6 @@ add_library(grpc++_test_util
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -5692,7 +5690,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -5854,7 +5851,6 @@ add_executable(test_core_iomgr_timer_list_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -5996,7 +5992,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -6119,7 +6114,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -6664,7 +6658,6 @@ add_executable(alts_security_connector_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -7040,7 +7033,6 @@ add_executable(auth_context_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -7135,7 +7127,6 @@ add_executable(authorization_matchers_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -7275,7 +7266,6 @@ add_executable(aws_request_signer_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -7579,7 +7569,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -7636,7 +7625,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -8250,7 +8238,6 @@ add_executable(buffer_list_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -9307,7 +9294,6 @@ add_executable(cel_authorization_engine_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -9682,7 +9668,6 @@ add_executable(channel_creds_registry_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -10015,7 +10000,6 @@ add_executable(check_gcp_environment_linux_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -10067,7 +10051,6 @@ add_executable(check_gcp_environment_windows_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -10867,7 +10850,6 @@ add_executable(cmdline_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -11008,7 +10990,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -11378,7 +11359,6 @@ add_executable(connectivity_state_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -12773,7 +12753,6 @@ add_executable(endpoint_pair_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -12924,7 +12903,6 @@ add_executable(error_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -12976,7 +12954,6 @@ add_executable(error_utils_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -13028,7 +13005,6 @@ add_executable(evaluate_args_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -13670,7 +13646,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -14390,7 +14365,6 @@ add_executable(format_request_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -14893,7 +14867,6 @@ add_executable(grpc_alts_credentials_options_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -14988,7 +14961,6 @@ add_executable(grpc_authorization_engine_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15040,7 +15012,6 @@ add_executable(grpc_authorization_policy_provider_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15428,7 +15399,6 @@ add_executable(grpc_ipv6_loopback_available_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15670,7 +15640,6 @@ add_executable(grpc_tls_certificate_distributor_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15722,7 +15691,6 @@ add_executable(grpc_tls_certificate_provider_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15774,7 +15742,6 @@ add_executable(grpc_tls_certificate_verifier_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15826,7 +15793,6 @@ add_executable(grpc_tls_credentials_options_comparator_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15878,7 +15844,6 @@ add_executable(grpc_tls_credentials_options_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -15934,6 +15899,7 @@ add_executable(grpc_tls_crl_provider_test
test/core/event_engine/event_engine_test_utils.cc
test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
test/core/security/grpc_tls_crl_provider_test.cc
test/core/tsi/transport_security_test_lib.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
@ -16613,7 +16579,6 @@ add_executable(histogram_test
test/core/util/histogram_test.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -16707,7 +16672,6 @@ add_executable(hpack_encoder_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -16759,7 +16723,6 @@ add_executable(hpack_parser_table_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -16811,7 +16774,6 @@ add_executable(hpack_parser_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -17531,7 +17493,6 @@ add_executable(insecure_security_connector_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -18196,7 +18157,6 @@ add_executable(json_token_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -18248,7 +18208,6 @@ add_executable(jwt_verifier_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -18983,7 +18942,6 @@ add_executable(matchers_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -19471,7 +19429,6 @@ add_executable(message_compress_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -19565,7 +19522,6 @@ add_executable(metadata_map_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -20870,7 +20826,6 @@ add_executable(parser_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -21194,7 +21149,6 @@ add_executable(ping_abuse_policy_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -21288,7 +21242,6 @@ add_executable(ping_configuration_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -21402,7 +21355,6 @@ add_executable(ping_rate_policy_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -22886,7 +22838,6 @@ add_executable(rbac_translator_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -23254,7 +23205,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -23308,7 +23258,6 @@ add_executable(resolve_address_using_ares_resolver_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -23362,7 +23311,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -23416,7 +23364,6 @@ add_executable(resolve_address_using_native_resolver_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -26121,7 +26068,6 @@ add_executable(secure_endpoint_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -26173,7 +26119,6 @@ add_executable(security_connector_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -26392,7 +26337,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -26464,7 +26408,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -26931,7 +26874,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -27242,7 +27184,6 @@ add_executable(settings_timeout_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -27968,7 +27909,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -28135,6 +28075,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_executable(ssl_transport_security_utils_test
test/core/tsi/ssl_transport_security_utils_test.cc
test/core/tsi/transport_security_test_lib.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
@ -28355,7 +28296,6 @@ add_executable(status_conversion_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -28703,7 +28643,6 @@ add_executable(streams_not_seen_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -28926,7 +28865,6 @@ add_executable(system_roots_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -29013,7 +28951,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -29112,7 +29049,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -29166,7 +29102,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -29603,7 +29538,6 @@ add_executable(test_core_iomgr_timer_heap_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -29655,7 +29589,6 @@ add_executable(test_core_security_credentials_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -29707,7 +29640,6 @@ add_executable(test_core_security_ssl_credentials_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -30634,7 +30566,6 @@ add_executable(timeout_encoding_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -30936,7 +30867,6 @@ add_executable(tls_security_connector_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -32503,7 +32433,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc
@ -33601,7 +33530,6 @@ add_executable(xds_credentials_test
test/core/util/histogram.cc
test/core/util/mock_endpoint.cc
test/core/util/parse_hexstring.cc
test/core/util/passthru_endpoint.cc
test/core/util/resolve_localhost_ip46.cc
test/core/util/slice_splitter.cc
test/core/util/tracer_util.cc

@ -73,11 +73,9 @@ EXPERIMENTS = {
],
"core_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
"cpp_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
"endpoint_test": [
"tcp_frame_size_tuning",
@ -90,9 +88,6 @@ EXPERIMENTS = {
"tcp_frame_size_tuning",
"tcp_rcv_lowat",
],
"lb_unit_test": [
"work_serializer_dispatch",
],
"logging_test": [
"promise_based_server_call",
],
@ -102,7 +97,6 @@ EXPERIMENTS = {
],
"xds_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
},
"on": {
@ -144,11 +138,9 @@ EXPERIMENTS = {
],
"core_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
"cpp_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
"endpoint_test": [
"tcp_frame_size_tuning",
@ -161,9 +153,6 @@ EXPERIMENTS = {
"tcp_frame_size_tuning",
"tcp_rcv_lowat",
],
"lb_unit_test": [
"work_serializer_dispatch",
],
"logging_test": [
"promise_based_server_call",
],
@ -173,7 +162,6 @@ EXPERIMENTS = {
],
"xds_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
},
"on": {
@ -212,11 +200,9 @@ EXPERIMENTS = {
"event_engine_client",
"promise_based_client_call",
"promise_based_server_call",
"work_serializer_dispatch",
],
"cpp_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
"endpoint_test": [
"tcp_frame_size_tuning",
@ -235,9 +221,6 @@ EXPERIMENTS = {
"lame_client_test": [
"promise_based_client_call",
],
"lb_unit_test": [
"work_serializer_dispatch",
],
"logging_test": [
"promise_based_server_call",
],
@ -247,7 +230,6 @@ EXPERIMENTS = {
],
"xds_end2end_test": [
"promise_based_server_call",
"work_serializer_dispatch",
],
},
"on": {
@ -256,6 +238,10 @@ EXPERIMENTS = {
],
"core_end2end_test": [
"event_engine_listener",
"work_serializer_dispatch",
],
"cpp_end2end_test": [
"work_serializer_dispatch",
],
"cpp_lb_end2end_test": [
"pick_first_happy_eyeballs",
@ -271,6 +257,7 @@ EXPERIMENTS = {
"lb_unit_test": [
"pick_first_happy_eyeballs",
"round_robin_delegate_to_pick_first",
"work_serializer_dispatch",
"wrr_delegate_to_pick_first",
],
"resolver_component_tests_runner_invoker": [
@ -282,6 +269,7 @@ EXPERIMENTS = {
"xds_end2end_test": [
"pick_first_happy_eyeballs",
"round_robin_delegate_to_pick_first",
"work_serializer_dispatch",
"wrr_delegate_to_pick_first",
],
},

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
gRPC Python Observability
====================
=========================
Module Contents
---------------

@ -18,6 +18,7 @@ API Reference
grpc_reflection
grpc_status
grpc_testing
grpc_observability
glossary

2
grpc.gyp generated

@ -1796,7 +1796,6 @@
'test/core/util/histogram.cc',
'test/core/util/mock_endpoint.cc',
'test/core/util/parse_hexstring.cc',
'test/core/util/passthru_endpoint.cc',
'test/core/util/resolve_localhost_ip46.cc',
'test/core/util/slice_splitter.cc',
'test/core/util/tracer_util.cc',
@ -1954,7 +1953,6 @@
'test/core/util/histogram.cc',
'test/core/util/mock_endpoint.cc',
'test/core/util/parse_hexstring.cc',
'test/core/util/passthru_endpoint.cc',
'test/core/util/resolve_localhost_ip46.cc',
'test/core/util/slice_splitter.cc',
'test/core/util/tracer_util.cc',

@ -3,7 +3,6 @@ coverage==4.5.4
cython==0.29.21
protobuf>=3.5.0.post1, < 4.0dev
wheel==0.38.1
google-auth==1.24.0
oauth2client==4.1.0
requests==2.25.1
urllib3==1.26.18
@ -13,12 +12,11 @@ idna==2.7
gevent==22.08.0
zope.event==4.5.0
setuptools==44.1.1
xds-protos==0.0.11
absl-py==1.4.0
google-cloud-trace==1.11.3
opencensus-context==0.1.3
google-cloud-monitoring==2.16.0
google-api-core==2.14.0
google-api-core==1.34.1
proto-plus==1.22.3
google-auth==2.23.4
googleapis-common-protos==1.61.0
@ -30,9 +28,9 @@ greenlet==1.1.3.post0
zope.interface==6.1
opentelemetry-sdk==1.21.0
opentelemetry-api==1.21.0
importlib-metadata==7.0.1
importlib-metadata==6.11.0
Deprecated==1.2.14
opentelemetry-semantic-conventions==0.43b0
opentelemetry-semantic-conventions==0.42b0
typing-extensions==4.9.0
pyasn1-modules==0.3.0
zipp==3.17.0

@ -294,6 +294,7 @@ const grpc_channel_filter MaxAgeFilter::kFilter =
MakePromiseBasedFilter<MaxAgeFilter, FilterEndpoint::kServer>("max_age");
void RegisterChannelIdleFilters(CoreConfiguration::Builder* builder) {
GPR_ASSERT(MaxAgeFilter::kFilter.init_call != nullptr);
if (!IsV3ChannelIdleFiltersEnabled()) return;
builder->channel_init()
->RegisterFilter<ClientIdleFilter>(GRPC_CLIENT_CHANNEL)

@ -67,7 +67,7 @@ namespace chaotic_good {
using grpc_event_engine::experimental::EventEngine;
namespace {
const int32_t kDataAlignmentBytes = 64;
const int32_t kTimeoutSecs = 5;
const int32_t kTimeoutSecs = 120;
} // namespace
ChaoticGoodConnector::ChaoticGoodConnector(

@ -70,7 +70,7 @@ namespace grpc_core {
namespace chaotic_good {
namespace {
const Duration kConnectionDeadline = Duration::Seconds(5);
const Duration kConnectionDeadline = Duration::Seconds(120);
} // namespace
using grpc_event_engine::experimental::EventEngine;

@ -1300,7 +1300,6 @@ static void null_then_sched_closure(grpc_closure** closure) {
}
void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
grpc_chttp2_stream* s,
grpc_closure** pclosure,
grpc_error_handle error,
const char* desc,
@ -1325,12 +1324,6 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
write_state_name(t->write_state), whence.file(), whence.line());
}
if (s->call_tracer) {
s->call_tracer->RecordAnnotation(
absl::StrFormat("on_complete: s=%p %p desc=%s err=%s", s, closure, desc,
grpc_core::StatusToString(error).c_str()));
}
if (!error.ok()) {
grpc_error_handle cl_err =
grpc_core::internal::StatusMoveFromHeapPtr(closure->error_data.error);
@ -1405,13 +1398,6 @@ static void perform_stream_op_locked(void* stream_op,
}
}
if (s->call_tracer) {
s->call_tracer->RecordAnnotation(absl::StrFormat(
"perform_stream_op_locked[s=%p; op=%p]: %s; on_complete = %p", s, op,
grpc_transport_stream_op_batch_string(op, true).c_str(),
op->on_complete));
}
grpc_closure* on_complete = op->on_complete;
// on_complete will be null if and only if there are no send ops in the batch.
if (on_complete != nullptr) {
@ -1483,7 +1469,7 @@ static void perform_stream_op_locked(void* stream_op,
} else {
s->send_initial_metadata = nullptr;
grpc_chttp2_complete_closure_step(
t, s, &s->send_initial_metadata_finished,
t, &s->send_initial_metadata_finished,
GRPC_ERROR_CREATE_REFERENCING(
"Attempt to send initial metadata after stream was closed",
&s->write_closed_error, 1),
@ -1503,7 +1489,7 @@ static void perform_stream_op_locked(void* stream_op,
// We should NOT return an error here, so as to avoid a cancel OP being
// started. The surface layer will notice that the stream has been closed
// for writes and fail the send message op.
grpc_chttp2_complete_closure_step(t, s, &s->send_message_finished,
grpc_chttp2_complete_closure_step(t, &s->send_message_finished,
absl::OkStatus(),
"fetching_send_message_finished");
} else {
@ -1543,7 +1529,7 @@ static void perform_stream_op_locked(void* stream_op,
int64_t notify_offset = s->next_message_end_offset;
if (notify_offset <= s->flow_controlled_bytes_written) {
grpc_chttp2_complete_closure_step(t, s, &s->send_message_finished,
grpc_chttp2_complete_closure_step(t, &s->send_message_finished,
absl::OkStatus(),
"fetching_send_message_finished");
} else {
@ -1587,7 +1573,7 @@ static void perform_stream_op_locked(void* stream_op,
s->send_trailing_metadata = nullptr;
s->sent_trailing_metadata_op = nullptr;
grpc_chttp2_complete_closure_step(
t, s, &s->send_trailing_metadata_finished,
t, &s->send_trailing_metadata_finished,
op->payload->send_trailing_metadata.send_trailing_metadata->empty()
? absl::OkStatus()
: GRPC_ERROR_CREATE("Attempt to send trailing metadata after "
@ -1640,7 +1626,7 @@ static void perform_stream_op_locked(void* stream_op,
}
if (on_complete != nullptr) {
grpc_chttp2_complete_closure_step(t, s, &on_complete, absl::OkStatus(),
grpc_chttp2_complete_closure_step(t, &on_complete, absl::OkStatus(),
"op->on_complete");
}
@ -2307,13 +2293,13 @@ static grpc_error_handle removal_error(grpc_error_handle extra_error,
return error;
}
static void flush_write_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
static void flush_write_list(grpc_chttp2_transport* t,
grpc_chttp2_write_cb** list,
grpc_error_handle error) {
while (*list) {
grpc_chttp2_write_cb* cb = *list;
*list = cb->next;
grpc_chttp2_complete_closure_step(t, s, &cb->closure, error,
grpc_chttp2_complete_closure_step(t, &cb->closure, error,
"on_write_finished_cb");
cb->next = t->write_cb_pool;
t->write_cb_pool = cb;
@ -2326,18 +2312,18 @@ void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
error =
removal_error(error, s, "Pending writes failed due to stream closure");
s->send_initial_metadata = nullptr;
grpc_chttp2_complete_closure_step(t, s, &s->send_initial_metadata_finished,
grpc_chttp2_complete_closure_step(t, &s->send_initial_metadata_finished,
error, "send_initial_metadata_finished");
s->send_trailing_metadata = nullptr;
s->sent_trailing_metadata_op = nullptr;
grpc_chttp2_complete_closure_step(t, s, &s->send_trailing_metadata_finished,
grpc_chttp2_complete_closure_step(t, &s->send_trailing_metadata_finished,
error, "send_trailing_metadata_finished");
grpc_chttp2_complete_closure_step(t, s, &s->send_message_finished, error,
grpc_chttp2_complete_closure_step(t, &s->send_message_finished, error,
"fetching_send_message_finished");
flush_write_list(t, s, &s->on_write_finished_cbs, error);
flush_write_list(t, s, &s->on_flow_controlled_cbs, error);
flush_write_list(t, &s->on_write_finished_cbs, error);
flush_write_list(t, &s->on_flow_controlled_cbs, error);
}
grpc_chttp2_transport::RemovedStreamHandle grpc_chttp2_mark_stream_closed(

@ -38,38 +38,41 @@ namespace grpc_core {
// sent over the wire. A data chunk being written over the wire is multiplexed
// with bytes from multiple RPCs. If one such RPC is traced, we store the
// following information about the traced RPC:
// - byte_offset_in_stream: Number of bytes belonging to that traced RPC which
// have been sent so far from the start of the RPC stream.
// - relative_start_pos_in_chunk: Starting offset of the traced RPC within
// the current chunk that is being sent.
// - num_traced_bytes_in_chunk: Number of bytes belonging to the traced RPC
// within the current chunk.
class ContextListEntry {
public:
ContextListEntry(void* context, int64_t relative_start_pos,
ContextListEntry(void* context, int64_t outbuf_offset,
int64_t num_traced_bytes, size_t byte_offset,
size_t stream_index,
std::shared_ptr<TcpTracerInterface> tcp_tracer)
: trace_context_(context),
relative_start_pos_in_chunk_(relative_start_pos),
outbuf_offset_(outbuf_offset),
num_traced_bytes_in_chunk_(num_traced_bytes),
byte_offset_in_stream_(byte_offset),
stream_index_(stream_index),
tcp_tracer_(std::move(tcp_tracer)) {}
ContextListEntry() = delete;
void* TraceContext() { return trace_context_; }
int64_t RelativeStartPosInChunk() { return relative_start_pos_in_chunk_; }
int64_t OutbufOffset() { return outbuf_offset_; }
int64_t NumTracedBytesInChunk() { return num_traced_bytes_in_chunk_; }
size_t ByteOffsetInStream() { return byte_offset_in_stream_; }
size_t StreamIndex() { return stream_index_; }
std::shared_ptr<TcpTracerInterface> ReleaseTcpTracer() {
return std::move(tcp_tracer_);
}
private:
void* trace_context_;
int64_t relative_start_pos_in_chunk_;
// Offset of the head of the current chunk in the output buffer.
int64_t outbuf_offset_;
// Number of bytes traced in the current chunk.
int64_t num_traced_bytes_in_chunk_;
// Offset of the head of the current chunk in the RPC stream.
size_t byte_offset_in_stream_;
// Index of the current chunk in the RPC stream.
// Set to zero for the first chunk of the RPC stream.
size_t stream_index_;
std::shared_ptr<TcpTracerInterface> tcp_tracer_;
};

@ -640,6 +640,9 @@ struct grpc_chttp2_stream {
/// Byte counter for number of bytes written
size_t byte_counter = 0;
/// Number of times written
int64_t write_counter = 0;
/// Only set when enabled.
grpc_core::CallTracerInterface* call_tracer = nullptr;
@ -775,7 +778,6 @@ void grpc_chttp2_add_incoming_goaway(grpc_chttp2_transport* t,
void grpc_chttp2_parsing_become_skip_parser(grpc_chttp2_transport* t);
void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
grpc_chttp2_stream* s,
grpc_closure** pclosure,
grpc_error_handle error,
const char* desc,

@ -82,10 +82,9 @@ static void add_to_write_list(grpc_chttp2_write_cb** list,
*list = cb;
}
static void finish_write_cb(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
grpc_chttp2_write_cb* cb, grpc_error_handle error) {
grpc_chttp2_complete_closure_step(t, s, &cb->closure, error,
"finish_write_cb");
static void finish_write_cb(grpc_chttp2_transport* t, grpc_chttp2_write_cb* cb,
grpc_error_handle error) {
grpc_chttp2_complete_closure_step(t, &cb->closure, error, "finish_write_cb");
cb->next = t->write_cb_pool;
t->write_cb_pool = cb;
}
@ -186,9 +185,9 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) {
});
}
static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
int64_t send_bytes, grpc_chttp2_write_cb** list,
int64_t* ctr, grpc_error_handle error) {
static bool update_list(grpc_chttp2_transport* t, int64_t send_bytes,
grpc_chttp2_write_cb** list, int64_t* ctr,
grpc_error_handle error) {
bool sched_any = false;
grpc_chttp2_write_cb* cb = *list;
*list = nullptr;
@ -197,7 +196,7 @@ static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
grpc_chttp2_write_cb* next = cb->next;
if (cb->call_at_byte <= *ctr) {
sched_any = true;
finish_write_cb(t, s, cb, error);
finish_write_cb(t, cb, error);
} else {
add_to_write_list(list, cb);
}
@ -424,8 +423,7 @@ class DataSendContext {
void CallCallbacks() {
if (update_list(
t_, s_,
static_cast<int64_t>(s_->sending_bytes - sending_bytes_before_),
t_, static_cast<int64_t>(s_->sending_bytes - sending_bytes_before_),
&s_->on_flow_controlled_cbs, &s_->flow_controlled_bytes_flowed,
absl::OkStatus())) {
write_context_->NoteScheduledResults();
@ -484,9 +482,9 @@ class StreamWriteContext {
s_->send_initial_metadata = nullptr;
s_->sent_initial_metadata = true;
write_context_->NoteScheduledResults();
grpc_chttp2_complete_closure_step(
t_, s_, &s_->send_initial_metadata_finished, absl::OkStatus(),
"send_initial_metadata_finished");
grpc_chttp2_complete_closure_step(t_, &s_->send_initial_metadata_finished,
absl::OkStatus(),
"send_initial_metadata_finished");
if (s_->call_tracer) {
grpc_core::HttpAnnotation::WriteStats write_stats;
write_stats.target_write_size = write_context_->target_write_size();
@ -583,9 +581,9 @@ class StreamWriteContext {
SentLastFrame();
write_context_->NoteScheduledResults();
grpc_chttp2_complete_closure_step(
t_, s_, &s_->send_trailing_metadata_finished, absl::OkStatus(),
"send_trailing_metadata_finished");
grpc_chttp2_complete_closure_step(t_, &s_->send_trailing_metadata_finished,
absl::OkStatus(),
"send_trailing_metadata_finished");
}
bool stream_became_writable() { return stream_became_writable_; }
@ -665,6 +663,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
// Add this stream to the list of the contexts to be traced at TCP
num_stream_bytes = t->outbuf.c_slice_buffer()->length - orig_len;
s->byte_counter += static_cast<size_t>(num_stream_bytes);
++s->write_counter;
if (s->traced && grpc_endpoint_can_track_err(t->ep)) {
grpc_core::CopyContextFn copy_context_fn =
grpc_core::GrpcHttp2GetCopyContextFn();
@ -672,7 +671,8 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
grpc_core::GrpcHttp2GetWriteTimestampsCallback() != nullptr) {
t->cl->emplace_back(copy_context_fn(s->context),
outbuf_relative_start_pos, num_stream_bytes,
s->byte_counter, s->tcp_tracer);
s->byte_counter, s->write_counter - 1,
s->tcp_tracer);
}
}
outbuf_relative_start_pos += num_stream_bytes;
@ -744,7 +744,7 @@ void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error) {
while (grpc_chttp2_list_pop_writing_stream(t, &s)) {
if (s->sending_bytes != 0) {
update_list(t, s, static_cast<int64_t>(s->sending_bytes),
update_list(t, static_cast<int64_t>(s->sending_bytes),
&s->on_write_finished_cbs, &s->flow_controlled_bytes_written,
error);
s->sending_bytes = 0;

@ -92,7 +92,9 @@ namespace {
Mutex* g_mu = new Mutex;
const grpc_channel_args* g_channel_args ABSL_GUARDED_BY(*g_mu) = nullptr;
GrpcXdsClient* g_xds_client ABSL_GUARDED_BY(*g_mu) = nullptr;
// Key bytes live in clients so they outlive the entries in this map
NoDestruct<std::map<absl::string_view, GrpcXdsClient*>> g_xds_client_map
ABSL_GUARDED_BY(*g_mu);
char* g_fallback_bootstrap_config ABSL_GUARDED_BY(*g_mu) = nullptr;
} // namespace
@ -139,9 +141,9 @@ absl::StatusOr<std::string> GetBootstrapContents(const char* fallback_config) {
std::vector<RefCountedPtr<GrpcXdsClient>> GetAllXdsClients() {
MutexLock lock(g_mu);
std::vector<RefCountedPtr<GrpcXdsClient>> xds_clients;
if (g_xds_client != nullptr) {
for (const auto& key_client : *g_xds_client_map) {
auto xds_client =
g_xds_client->RefIfNonZero(DEBUG_LOCATION, "DumpAllClientConfigs");
key_client.second->RefIfNonZero(DEBUG_LOCATION, "DumpAllClientConfigs");
if (xds_client != nullptr) {
xds_clients.emplace_back(xds_client.TakeAsSubclass<GrpcXdsClient>());
}
@ -152,7 +154,7 @@ std::vector<RefCountedPtr<GrpcXdsClient>> GetAllXdsClients() {
} // namespace
absl::StatusOr<RefCountedPtr<GrpcXdsClient>> GrpcXdsClient::GetOrCreate(
const ChannelArgs& args, const char* reason) {
absl::string_view key, const ChannelArgs& args, const char* reason) {
// If getting bootstrap from channel args, create a local XdsClient
// instance for the channel or server instead of using the global instance.
absl::optional<absl::string_view> bootstrap_config = args.GetString(
@ -164,13 +166,14 @@ absl::StatusOr<RefCountedPtr<GrpcXdsClient>> GrpcXdsClient::GetOrCreate(
GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS);
auto channel_args = ChannelArgs::FromC(xds_channel_args);
return MakeRefCounted<GrpcXdsClient>(
std::move(*bootstrap), channel_args,
key, std::move(*bootstrap), channel_args,
MakeOrphanable<GrpcXdsTransportFactory>(channel_args));
}
// Otherwise, use the global instance.
MutexLock lock(g_mu);
if (g_xds_client != nullptr) {
auto xds_client = g_xds_client->RefIfNonZero(DEBUG_LOCATION, reason);
auto it = g_xds_client_map->find(key);
if (it != g_xds_client_map->end()) {
auto xds_client = it->second->RefIfNonZero(DEBUG_LOCATION, reason);
if (xds_client != nullptr) {
return xds_client.TakeAsSubclass<GrpcXdsClient>();
}
@ -188,9 +191,13 @@ absl::StatusOr<RefCountedPtr<GrpcXdsClient>> GrpcXdsClient::GetOrCreate(
// Instantiate XdsClient.
auto channel_args = ChannelArgs::FromC(g_channel_args);
auto xds_client = MakeRefCounted<GrpcXdsClient>(
std::move(*bootstrap), channel_args,
key, std::move(*bootstrap), channel_args,
MakeOrphanable<GrpcXdsTransportFactory>(channel_args));
g_xds_client = xds_client.get();
g_xds_client_map->emplace(xds_client->key(), xds_client.get());
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
gpr_log(GPR_INFO, "xDS client for key: %s was created",
std::string(key).c_str());
}
return xds_client;
}
@ -211,6 +218,8 @@ grpc_slice GrpcXdsClient::DumpAllClientConfigs()
arena.ptr());
xds_client->mu()->Lock();
xds_client->DumpClientConfig(&string_pool, arena.ptr(), client_config);
envoy_service_status_v3_ClientConfig_set_client_scope(
client_config, StdStringToUpbString(xds_client->key()));
}
// Serialize the upb message to bytes
size_t output_length;
@ -223,7 +232,8 @@ grpc_slice GrpcXdsClient::DumpAllClientConfigs()
}
GrpcXdsClient::GrpcXdsClient(
std::unique_ptr<GrpcXdsBootstrap> bootstrap, const ChannelArgs& args,
absl::string_view key, std::unique_ptr<GrpcXdsBootstrap> bootstrap,
const ChannelArgs& args,
OrphanablePtr<XdsTransportFactory> transport_factory)
: XdsClient(
std::move(bootstrap), std::move(transport_factory),
@ -237,13 +247,18 @@ GrpcXdsClient::GrpcXdsClient(
args.GetDurationFromIntMillis(
GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS)
.value_or(Duration::Seconds(15)))),
key_(key),
certificate_provider_store_(MakeOrphanable<CertificateProviderStore>(
static_cast<const GrpcXdsBootstrap&>(this->bootstrap())
.certificate_providers())) {}
GrpcXdsClient::~GrpcXdsClient() {
void GrpcXdsClient::Orphan() {
MutexLock lock(g_mu);
if (g_xds_client == this) g_xds_client = nullptr;
auto it = g_xds_client_map->find(key_);
if (it != g_xds_client_map->end() && it->second == this) {
g_xds_client_map->erase(it);
}
XdsClient::Orphan();
}
grpc_pollset_set* GrpcXdsClient::interested_parties() const {
@ -258,9 +273,9 @@ void SetXdsChannelArgsForTest(grpc_channel_args* args) {
g_channel_args = args;
}
void UnsetGlobalXdsClientForTest() {
void UnsetGlobalXdsClientsForTest() {
MutexLock lock(g_mu);
g_xds_client = nullptr;
g_xds_client_map->clear();
}
void SetXdsFallbackBootstrapConfig(const char* config) {

@ -43,7 +43,7 @@ class GrpcXdsClient : public XdsClient {
public:
// Factory function to get or create the global XdsClient instance.
static absl::StatusOr<RefCountedPtr<GrpcXdsClient>> GetOrCreate(
const ChannelArgs& args, const char* reason);
absl::string_view key, const ChannelArgs& args, const char* reason);
// Builds ClientStatusResponse containing all resources from all XdsClients
static grpc_slice DumpAllClientConfigs();
@ -60,10 +60,12 @@ class GrpcXdsClient : public XdsClient {
// work for callers that use interested_parties() but not for callers
// that also use certificate_provider_store(), but we should consider
// alternatives for that case as well.
GrpcXdsClient(std::unique_ptr<GrpcXdsBootstrap> bootstrap,
GrpcXdsClient(absl::string_view key,
std::unique_ptr<GrpcXdsBootstrap> bootstrap,
const ChannelArgs& args,
OrphanablePtr<XdsTransportFactory> transport_factory);
~GrpcXdsClient() override;
void Orphan() override;
// Helpers for encoding the XdsClient object in channel args.
static absl::string_view ChannelArgName() {
@ -79,13 +81,16 @@ class GrpcXdsClient : public XdsClient {
return *certificate_provider_store_;
}
absl::string_view key() const { return key_; }
private:
std::string key_;
OrphanablePtr<CertificateProviderStore> certificate_provider_store_;
};
namespace internal {
void SetXdsChannelArgsForTest(grpc_channel_args* args);
void UnsetGlobalXdsClientForTest();
void UnsetGlobalXdsClientsForTest();
// Sets bootstrap config to be used when no env var is set.
// Does not take ownership of config.
void SetXdsFallbackBootstrapConfig(const char* config);

@ -94,6 +94,8 @@ namespace {
using ReadDelayHandle = XdsClient::ReadDelayHandle;
constexpr absl::string_view kServerXdsClientKey = "#server";
TraceFlag grpc_xds_server_config_fetcher_trace(false,
"xds_server_config_fetcher");
@ -1372,7 +1374,7 @@ grpc_server_config_fetcher* grpc_server_config_fetcher_xds_create(
"update=%p, user_data=%p}, args=%p)",
3, (notifier.on_serving_status_update, notifier.user_data, args));
auto xds_client = grpc_core::GrpcXdsClient::GetOrCreate(
channel_args, "XdsServerConfigFetcher");
grpc_core::kServerXdsClientKey, channel_args, "XdsServerConfigFetcher");
if (!xds_client.ok()) {
gpr_log(GPR_ERROR, "Failed to create xds client: %s",
xds_client.status().ToString().c_str());

@ -1065,8 +1065,10 @@ MakeFilterCall(Derived* derived) {
// the filter does not intercept call finalization.
// - void OnFinalize(const grpc_call_final_info*):
// the filter intercepts call finalization.
class ImplementChannelFilterTag {};
template <typename Derived>
class ImplementChannelFilter : public ChannelFilter {
class ImplementChannelFilter : public ChannelFilter,
public ImplementChannelFilterTag {
public:
// Natively construct a v3 call.
void InitCall(CallSpineInterface* call_spine) {
@ -1914,7 +1916,7 @@ struct ChannelFilterWithFlagsMethods {
template <typename F, FilterEndpoint kEndpoint, uint8_t kFlags = 0>
absl::enable_if_t<
std::is_base_of<ChannelFilter, F>::value &&
!std::is_base_of<ImplementChannelFilter<F>, F>::value &&
!std::is_base_of<ImplementChannelFilterTag, F>::value &&
!std::is_base_of<HackyHackyHackySkipInV3FilterStacks, F>::value,
grpc_channel_filter>
MakePromiseBasedFilter(const char* name) {
@ -2001,7 +2003,7 @@ MakePromiseBasedFilter(const char* name) {
}
template <typename F, FilterEndpoint kEndpoint, uint8_t kFlags = 0>
absl::enable_if_t<std::is_base_of<ImplementChannelFilter<F>, F>::value,
absl::enable_if_t<std::is_base_of<ImplementChannelFilterTag, F>::value,
grpc_channel_filter>
MakePromiseBasedFilter(const char* name) {
using CallData = promise_filter_detail::CallData<kEndpoint>;

@ -169,6 +169,7 @@ absl::Status PrepareSocket(const PosixTcpOptions& options,
!ResolvedAddressIsVSock(socket.addr)) {
GRPC_RETURN_IF_ERROR(socket.sock.SetSocketLowLatency(1));
GRPC_RETURN_IF_ERROR(socket.sock.SetSocketReuseAddr(1));
GRPC_RETURN_IF_ERROR(socket.sock.SetSocketDscp(options.dscp));
socket.sock.TrySetSocketTcpUserTimeout(options, false);
}
GRPC_RETURN_IF_ERROR(socket.sock.SetSocketNoSigpipeIfPossible());

@ -201,7 +201,7 @@ void PrintExperimentsList() {
for (auto name_index : visitation_order) {
const size_t i = name_index.second;
gpr_log(
GPR_DEBUG, "%s",
GPR_INFO, "%s",
absl::StrCat(
"gRPC EXPERIMENT ", g_experiment_metadata[i].name,
std::string(max_experiment_length -

@ -792,7 +792,7 @@ const ExperimentMetadata g_experiment_metadata[] = {
true},
{"work_serializer_dispatch", description_work_serializer_dispatch,
additional_constraints_work_serializer_dispatch,
required_experiments_work_serializer_dispatch, 1, false, true},
required_experiments_work_serializer_dispatch, 1, true, true},
{"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first,
additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true},
};

@ -232,7 +232,8 @@ inline bool IsV3CompressionFilterEnabled() { return false; }
inline bool IsV3ServerAuthFilterEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE
inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; }
inline bool IsWorkSerializerDispatchEnabled() { return false; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_DISPATCH
inline bool IsWorkSerializerDispatchEnabled() { return true; }
#define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST
inline bool IsWrrDelegateToPickFirstEnabled() { return true; }
#endif

@ -123,6 +123,11 @@
- name: work_serializer_clears_time_cache
default: true
- name: work_serializer_dispatch
default: false
default:
# TODO(ysseung): Not fully tested.
ios: broken
posix: true
# TODO(ysseung): Test flakes not fully resolved.
windows: broken
- name: wrr_delegate_to_pick_first
default: true

@ -173,6 +173,8 @@ class Arena {
}
}
// Allocates T from the arena.
// The caller is responsible for calling p->~T(), but should NOT delete.
// TODO(roth): We currently assume that all callers need alignment of 16
// bytes, which may be wrong in some cases. When we have time, we should
// change this to instead use the alignment of the type being allocated by
@ -185,6 +187,7 @@ class Arena {
}
// Like New, but has the arena call p->~T() at arena destruction time.
// The caller should NOT delete.
template <typename T, typename... Args>
T* ManagedNew(Args&&... args) {
auto* p = New<ManagedNewImpl<T>>(std::forward<Args>(args)...);

@ -53,15 +53,22 @@ namespace grpc_core {
namespace experimental {
namespace {
std::string IssuerFromCrl(X509_CRL* crl) {
// TODO(gtcooke94) Move ssl_transport_security_utils to it's own BUILD target
// and add this to it.
absl::StatusOr<std::string> IssuerFromCrl(X509_CRL* crl) {
if (crl == nullptr) {
return "";
return absl::InvalidArgumentError("crl cannot be null");
}
char* buf = X509_NAME_oneline(X509_CRL_get_issuer(crl), nullptr, 0);
std::string ret;
if (buf != nullptr) {
ret = buf;
X509_NAME* issuer = X509_CRL_get_issuer(crl);
if (issuer == nullptr) {
return absl::InvalidArgumentError("crl cannot have null issuer");
}
unsigned char* buf = nullptr;
int len = i2d_X509_NAME(issuer, &buf);
if (len < 0 || buf == nullptr) {
return absl::InvalidArgumentError("crl cannot have null issuer");
}
std::string ret(reinterpret_cast<char const*>(buf), len);
OPENSSL_free(buf);
return ret;
}
@ -103,11 +110,11 @@ absl::StatusOr<std::unique_ptr<Crl>> Crl::Parse(absl::string_view crl_string) {
}
absl::StatusOr<std::unique_ptr<CrlImpl>> CrlImpl::Create(X509_CRL* crl) {
std::string issuer = IssuerFromCrl(crl);
if (issuer.empty()) {
return absl::InvalidArgumentError("Issuer of crl cannot be empty");
absl::StatusOr<std::string> issuer = IssuerFromCrl(crl);
if (!issuer.ok()) {
return issuer.status();
}
return std::make_unique<CrlImpl>(crl, issuer);
return std::make_unique<CrlImpl>(crl, *issuer);
}
CrlImpl::~CrlImpl() { X509_CRL_free(crl_); }

@ -648,31 +648,12 @@ class FilterStackCall final : public Call {
}
bool completed_batch_step(PendingOp op) {
auto mask = PendingOpMask(op);
// Acquire call tracer before ops_pending_.fetch_sub to avoid races with
// call_ being set to nullptr in PostCompletion method. Store the
// call_tracer_ and call_ variables locally as well because they could be
// modified by another thread after the fetch_sub operation.
CallTracerAnnotationInterface* call_tracer = call_tracer_;
FilterStackCall* call = call_;
bool is_call_trace_enabled = grpc_call_trace.enabled();
bool is_call_ops_annotate_enabled =
(IsTraceRecordCallopsEnabled() && call_tracer != nullptr);
if (is_call_ops_annotate_enabled) {
call->InternalRef("Call ops annotate");
}
auto r = ops_pending_.fetch_sub(mask, std::memory_order_acq_rel);
if (is_call_trace_enabled || is_call_ops_annotate_enabled) {
std::string trace_string = absl::StrFormat(
"BATCH:%p COMPLETE:%s REMAINING:%s (tag:%p)", this,
PendingOpString(mask).c_str(), PendingOpString(r & ~mask).c_str(),
completion_data_.notify_tag.tag);
if (is_call_trace_enabled) {
gpr_log(GPR_DEBUG, "%s", trace_string.c_str());
}
if (is_call_ops_annotate_enabled) {
call_tracer->RecordAnnotation(trace_string);
call->InternalUnref("Call ops annotate");
}
if (grpc_call_trace.enabled()) {
gpr_log(GPR_DEBUG, "BATCH:%p COMPLETE:%s REMAINING:%s (tag:%p)", this,
PendingOpString(mask).c_str(),
PendingOpString(r & ~mask).c_str(),
completion_data_.notify_tag.tag);
}
GPR_ASSERT((r & mask) != 0);
return r == mask;
@ -1538,7 +1519,6 @@ grpc_call_error FilterStackCall::StartBatch(const grpc_op* ops, size_t nops,
grpc_transport_stream_op_batch_payload* stream_op_payload;
uint32_t seen_ops = 0;
intptr_t pending_ops = 0;
CallTracerAnnotationInterface* call_tracer = nullptr;
for (i = 0; i < nops; i++) {
if (seen_ops & (1u << ops[i].op)) {
@ -1899,15 +1879,6 @@ grpc_call_error FilterStackCall::StartBatch(const grpc_op* ops, size_t nops,
stream_op->on_complete = &bctl->finish_batch_;
}
call_tracer = static_cast<CallTracerAnnotationInterface*>(
ContextGet(GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE));
if ((IsTraceRecordCallopsEnabled() && call_tracer != nullptr)) {
call_tracer->RecordAnnotation(absl::StrFormat(
"BATCH:%p START:%s BATCH:%s (tag:%p)", bctl,
PendingOpString(pending_ops).c_str(),
grpc_transport_stream_op_batch_string(stream_op, true).c_str(),
bctl->completion_data_.notify_tag.tag));
}
if (grpc_call_trace.enabled()) {
gpr_log(GPR_DEBUG, "BATCH:%p START:%s BATCH:%s (tag:%p)", bctl,
PendingOpString(pending_ops).c_str(),

@ -136,8 +136,8 @@ void grpc_shutdown_internal_locked(void)
g_shutting_down_cv->SignalAll();
}
void grpc_shutdown_internal(void* /*ignored*/) {
GRPC_API_TRACE("grpc_shutdown_internal", 0, ());
void grpc_shutdown_from_cleanup_thread(void* /*ignored*/) {
GRPC_API_TRACE("grpc_shutdown_from_cleanup_thread", 0, ());
grpc_core::MutexLock lock(g_init_mu);
// We have released lock from the shutdown thread and it is possible that
// another grpc_init has been called, and do nothing if that is the case.
@ -145,6 +145,7 @@ void grpc_shutdown_internal(void* /*ignored*/) {
return;
}
grpc_shutdown_internal_locked();
gpr_log(GPR_DEBUG, "grpc_shutdown from cleanup thread done");
}
void grpc_shutdown(void) {
@ -165,6 +166,7 @@ void grpc_shutdown(void) {
gpr_log(GPR_DEBUG, "grpc_shutdown starts clean-up now");
g_shutting_down = true;
grpc_shutdown_internal_locked();
gpr_log(GPR_DEBUG, "grpc_shutdown done");
} else {
// spawn a detached thread to do the actual clean up in case we are
// currently in an executor thread.
@ -172,7 +174,7 @@ void grpc_shutdown(void) {
g_initializations++;
g_shutting_down = true;
grpc_core::Thread cleanup_thread(
"grpc_shutdown", grpc_shutdown_internal, nullptr, nullptr,
"grpc_shutdown", grpc_shutdown_from_cleanup_thread, nullptr, nullptr,
grpc_core::Thread::Options().set_joinable(false).set_tracked(false));
cleanup_thread.Start();
}

@ -880,7 +880,8 @@ void XdsResolver::ClusterSelectionFilter::Call::OnClientInitialMetadata(
//
void XdsResolver::StartLocked() {
auto xds_client = GrpcXdsClient::GetOrCreate(args_, "xds resolver");
auto xds_client =
GrpcXdsClient::GetOrCreate(uri_.ToString(), args_, "xds resolver");
if (!xds_client.ok()) {
gpr_log(GPR_ERROR,
"Failed to create xds client -- channel will remain in "

@ -1004,15 +1004,14 @@ static int GetCrlFromProvider(X509_STORE_CTX* ctx, X509_CRL** crl_out,
auto* provider = static_cast<grpc_core::experimental::CrlProvider*>(
SSL_CTX_get_ex_data(ssl_ctx, g_ssl_ctx_ex_crl_provider_index));
char* buf = X509_NAME_oneline(X509_get_issuer_name(cert), nullptr, 0);
if (buf == nullptr) {
gpr_log(GPR_ERROR, "Certificate has null issuer, cannot do CRL lookup");
absl::StatusOr<std::string> issuer_name = grpc_core::IssuerFromCert(cert);
if (!issuer_name.ok()) {
gpr_log(GPR_INFO, "Could not get certificate issuer name");
return 0;
}
grpc_core::experimental::CertificateInfoImpl cert_impl(buf);
grpc_core::experimental::CertificateInfoImpl cert_impl(*issuer_name);
std::shared_ptr<grpc_core::experimental::Crl> internal_crl =
provider->GetCrl(cert_impl);
OPENSSL_free(buf);
// There wasn't a CRL found in the provider. Returning 0 will end up causing
// OpenSSL to return X509_V_ERR_UNABLE_TO_GET_CRL. We then catch that error
// and behave how we want for a missing CRL.

@ -23,6 +23,10 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "src/core/tsi/transport_security_interface.h"
@ -247,4 +251,70 @@ tsi_result SslProtectorUnprotect(const unsigned char* protected_frames_bytes,
return result;
}
bool VerifyCrlSignature(X509_CRL* crl, X509* issuer) {
if (issuer == nullptr || crl == nullptr) {
return false;
}
EVP_PKEY* ikey = X509_get_pubkey(issuer);
if (ikey == nullptr) {
// Can't verify signature because we couldn't get the pubkey, fail the
// check.
EVP_PKEY_free(ikey);
return false;
}
bool ret = X509_CRL_verify(crl, ikey) == 1;
EVP_PKEY_free(ikey);
return ret;
}
bool VerifyCrlCertIssuerNamesMatch(X509_CRL* crl, X509* cert) {
if (cert == nullptr || crl == nullptr) {
return false;
}
X509_NAME* cert_issuer_name = X509_get_issuer_name(cert);
if (cert == nullptr) {
return false;
}
X509_NAME* crl_issuer_name = X509_CRL_get_issuer(crl);
if (crl_issuer_name == nullptr) {
return false;
}
return X509_NAME_cmp(cert_issuer_name, crl_issuer_name) == 0;
}
bool HasCrlSignBit(X509* cert) {
if (cert == nullptr) {
return false;
}
// X509_get_key_usage was introduced in 1.1.1
// A missing key usage extension means all key usages are valid.
#if OPENSSL_VERSION_NUMBER < 0x10100000
// X509_check_ca sets cert->ex_flags. We dont use the return value, but those
// flags being set is important.
// https://github.com/openssl/openssl/blob/e818b74be2170fbe957a07b0da4401c2b694b3b8/crypto/x509v3/v3_purp.c#L585
X509_check_ca(cert);
if (!(cert->ex_flags & EXFLAG_KUSAGE)) {
return true;
}
return (cert->ex_kusage & KU_CRL_SIGN) != 0;
#else
return (X509_get_key_usage(cert) & KU_CRL_SIGN) != 0;
#endif // OPENSSL_VERSION_NUMBER < 0x10100000
}
absl::StatusOr<std::string> IssuerFromCert(X509* cert) {
if (cert == nullptr) {
return absl::InvalidArgumentError("cert cannot be null");
}
X509_NAME* issuer = X509_get_issuer_name(cert);
unsigned char* buf = nullptr;
int len = i2d_X509_NAME(issuer, &buf);
if (len < 0 || buf == nullptr) {
return absl::InvalidArgumentError("could not read issuer name from cert");
}
std::string ret(reinterpret_cast<char const*>(buf), len);
OPENSSL_free(buf);
return ret;
}
} // namespace grpc_core

@ -23,6 +23,8 @@
#include <openssl/x509.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include <grpc/grpc_security_constants.h>
@ -142,6 +144,22 @@ tsi_result SslProtectorUnprotect(const unsigned char* protected_frames_bytes,
unsigned char* unprotected_bytes,
size_t* unprotected_bytes_size);
// Verifies that `crl` was signed by `issuer.
// return: true if valid, false otherwise.
bool VerifyCrlSignature(X509_CRL* crl, X509* issuer);
// Verifies the CRL issuer and certificate issuer name match.
// return: true if equal, false if not.
bool VerifyCrlCertIssuerNamesMatch(X509_CRL* crl, X509* cert);
// Verifies the certificate in question has the cRLSign bit present.
// return: true if cRLSign bit is present, false otherwise.
bool HasCrlSignBit(X509* cert);
// Gets a stable representation of the issuer name from an X509 certificate.
// return: a std::string of the DER encoding of the X509_NAME issuer name.
absl::StatusOr<std::string> IssuerFromCert(X509* cert);
} // namespace grpc_core
#endif // GRPC_SRC_CORE_TSI_SSL_TRANSPORT_SECURITY_UTILS_H

@ -74,11 +74,11 @@ class ObservabilityPlugin(
interface and wrapped in a PyCapsule using `client_call_tracer` as name.
Args:
method_name: The method name of the call in byte format.
target: The channel target of the call in byte format.
method_name: The method name of the call in byte format.
target: The channel target of the call in byte format.
Returns:
A PyCapsule which stores a ClientCallTracer object.
A PyCapsule which stores a ClientCallTracer object.
"""
raise NotImplementedError()
@ -95,7 +95,7 @@ class ObservabilityPlugin(
interface and wrapped in a PyCapsule using `client_call_tracer` as name.
Args:
client_call_tracer: A PyCapsule which stores a ClientCallTracer object.
client_call_tracer: A PyCapsule which stores a ClientCallTracer object.
"""
raise NotImplementedError()
@ -111,12 +111,12 @@ class ObservabilityPlugin(
This method can be used to propagate census context.
Args:
trace_id: The identifier for the trace associated with the span as a
32-character hexadecimal encoded string,
e.g. 26ed0036f2eff2b7317bccce3e28d01f
span_id: The identifier for the span as a 16-character hexadecimal encoded
string. e.g. 113ec879e62583bc
is_sampled: A bool indicates whether the span is sampled.
trace_id: The identifier for the trace associated with the span as a
32-character hexadecimal encoded string,
e.g. 26ed0036f2eff2b7317bccce3e28d01f
span_id: The identifier for the span as a 16-character hexadecimal encoded
string. e.g. 113ec879e62583bc
is_sampled: A bool indicates whether the span is sampled.
"""
raise NotImplementedError()
@ -135,7 +135,7 @@ class ObservabilityPlugin(
using `server_call_tracer_factory` as name.
Returns:
A PyCapsule which stores a ServerCallTracerFactory object.
A PyCapsule which stores a ServerCallTracerFactory object.
"""
raise NotImplementedError()
@ -149,12 +149,12 @@ class ObservabilityPlugin(
called at the end of each RPC.
Args:
method: The fully-qualified name of the RPC method being invoked.
target: The target name of the RPC method being invoked.
rpc_latency: The latency for the RPC in seconds, equals to the time between
when the client invokes the RPC and when the client receives the status.
status_code: An element of grpc.StatusCode in string format representing the
final status for the RPC.
method: The fully-qualified name of the RPC method being invoked.
target: The target name of the RPC method being invoked.
rpc_latency: The latency for the RPC in seconds, equals to the time between
when the client invokes the RPC and when the client receives the status.
status_code: An element of grpc.StatusCode in string format representing the
final status for the RPC.
"""
raise NotImplementedError()
@ -162,7 +162,7 @@ class ObservabilityPlugin(
"""Enable or disable tracing.
Args:
enable: A bool indicates whether tracing should be enabled.
enable: A bool indicates whether tracing should be enabled.
"""
self._tracing_enabled = enable
@ -170,7 +170,7 @@ class ObservabilityPlugin(
"""Enable or disable stats(metrics).
Args:
enable: A bool indicates whether stats should be enabled.
enable: A bool indicates whether stats should be enabled.
"""
self._stats_enabled = enable
@ -192,7 +192,7 @@ def get_plugin() -> Generator[Optional[ObservabilityPlugin], None, None]:
"""Get the ObservabilityPlugin in _observability module.
Returns:
The ObservabilityPlugin currently registered with the _observability
The ObservabilityPlugin currently registered with the _observability
module. Or None if no plugin exists at the time of calling this method.
"""
with _plugin_lock:
@ -203,11 +203,11 @@ def set_plugin(observability_plugin: Optional[ObservabilityPlugin]) -> None:
"""Save ObservabilityPlugin to _observability module.
Args:
observability_plugin: The ObservabilityPlugin to save.
observability_plugin: The ObservabilityPlugin to save.
Raises:
ValueError: If an ObservabilityPlugin was already registered at the
time of calling this method.
time of calling this method.
"""
global _OBSERVABILITY_PLUGIN # pylint: disable=global-statement
with _plugin_lock:
@ -223,11 +223,11 @@ def observability_init(observability_plugin: ObservabilityPlugin) -> None:
channels/servers are built.
Args:
observability_plugin: The ObservabilityPlugin to use.
observability_plugin: The ObservabilityPlugin to use.
Raises:
ValueError: If an ObservabilityPlugin was already registered at the
time of calling this method.
time of calling this method.
"""
set_plugin(observability_plugin)
try:
@ -256,7 +256,7 @@ def delete_call_tracer(client_call_tracer_capsule: Any) -> None:
interface and wrapped in a PyCapsule using `client_call_tracer` as the name.
Args:
client_call_tracer_capsule: A PyCapsule which stores a ClientCallTracer object.
client_call_tracer_capsule: A PyCapsule which stores a ClientCallTracer object.
"""
with get_plugin() as plugin:
if not (plugin and plugin.observability_enabled):
@ -270,8 +270,8 @@ def maybe_record_rpc_latency(state: "_channel._RPCState") -> None:
This method will be called at the end of each RPC.
Args:
state: a grpc._channel._RPCState object which contains the stats related to the
RPC.
state: a grpc._channel._RPCState object which contains the stats related to the
RPC.
"""
# TODO(xuanwn): use channel args to exclude those metrics.
for exclude_prefix in _SERVICES_TO_EXCLUDE:

@ -476,7 +476,7 @@ class _InterceptedStreamResponseMixin:
_response_aiter: Optional[AsyncIterable[ResponseType]]
def _init_stream_response_mixin(self) -> None:
# Is initalized later, otherwise if the iterator is not finnally
# Is initalized later, otherwise if the iterator is not finally
# consumed a logging warning is emmited by Asyncio.
self._response_aiter = None

@ -57,7 +57,7 @@ GCC-like stuff, but you may end up having a bad time.
Dependencies
-------------------------
------------
gRPC Python Observability Depends on the following packages:
::

@ -569,6 +569,7 @@ grpc_cc_test(
srcs = ["grpc_tls_crl_provider_test.cc"],
data = [
"//test/core/tsi/test_creds/crl_data:ca.pem",
"//test/core/tsi/test_creds/crl_data:intermediate_ca.pem",
"//test/core/tsi/test_creds/crl_data/crls:ab06acdd.r0",
"//test/core/tsi/test_creds/crl_data/crls:b9322cac.r0",
"//test/core/tsi/test_creds/crl_data/crls:current.crl",
@ -585,6 +586,7 @@ grpc_cc_test(
"//test/core/event_engine:event_engine_test_utils",
"//test/core/event_engine/fuzzing_event_engine",
"//test/core/event_engine/fuzzing_event_engine:fuzzing_event_engine_proto",
"//test/core/tsi:transport_security_test_lib",
"//test/core/util:fuzz_config_vars_proto",
"//test/core/util:grpc_test_util",
],

@ -40,16 +40,15 @@
#include "test/core/event_engine/event_engine_test_utils.h"
#include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
#include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h"
#include "test/core/tsi/transport_security_test_lib.h"
#include "test/core/util/test_config.h"
#include "test/core/util/tls_utils.h"
static constexpr absl::string_view kCrlPath =
"test/core/tsi/test_creds/crl_data/crls/current.crl";
static constexpr absl::string_view kCrlName = "current.crl";
static constexpr absl::string_view kCrlIssuer =
"/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=testca";
static constexpr absl::string_view kCrlIntermediateIssuer =
"/CN=intermediatecert.example.com";
static constexpr absl::string_view kCrlIntermediateIssuerPath =
"test/core/tsi/test_creds/crl_data/intermediate_ca.pem";
static constexpr absl::string_view kCrlDirectory =
"test/core/tsi/test_creds/crl_data/crls";
static constexpr absl::string_view kRootCert =
@ -88,9 +87,35 @@ class FakeDirectoryReader : public DirectoryReader {
std::vector<std::string>();
};
class DirectoryReloaderCrlProviderTest : public ::testing::Test {
class CrlProviderTest : public ::testing::Test {
public:
void SetUp() override {
std::string pem_cert = GetFileContents(kRootCert.data());
X509* issuer = ReadPemCert(pem_cert);
auto base_crl_issuer = IssuerFromCert(issuer);
ASSERT_EQ(base_crl_issuer.status(), absl::OkStatus());
base_crl_issuer_ = *base_crl_issuer;
std::string intermediate_string =
GetFileContents(kCrlIntermediateIssuerPath.data());
X509* intermediate_issuer = ReadPemCert(intermediate_string);
auto intermediate_crl_issuer = IssuerFromCert(intermediate_issuer);
ASSERT_EQ(intermediate_crl_issuer.status(), absl::OkStatus());
intermediate_crl_issuer_ = *intermediate_crl_issuer;
X509_free(issuer);
X509_free(intermediate_issuer);
}
void TearDown() override {}
protected:
std::string base_crl_issuer_;
std::string intermediate_crl_issuer_;
};
class DirectoryReloaderCrlProviderTest : public CrlProviderTest {
public:
void SetUp() override {
CrlProviderTest::SetUp();
event_engine_ =
std::make_shared<grpc_event_engine::experimental::FuzzingEventEngine>(
grpc_event_engine::experimental::FuzzingEventEngine::Options(),
@ -140,15 +165,15 @@ class DirectoryReloaderCrlProviderTest : public ::testing::Test {
event_engine_;
};
TEST(CrlProviderTest, CanParseCrl) {
TEST_F(CrlProviderTest, CanParseCrl) {
std::string crl_string = GetFileContents(kCrlPath.data());
absl::StatusOr<std::shared_ptr<Crl>> crl = Crl::Parse(crl_string);
ASSERT_TRUE(crl.ok()) << crl.status();
ASSERT_NE(*crl, nullptr);
EXPECT_EQ((*crl)->Issuer(), kCrlIssuer);
EXPECT_EQ((*crl)->Issuer(), base_crl_issuer_);
}
TEST(CrlProviderTest, InvalidFile) {
TEST_F(CrlProviderTest, InvalidFile) {
std::string crl_string = "INVALID CRL FILE";
absl::StatusOr<std::shared_ptr<Crl>> crl = Crl::Parse(crl_string);
EXPECT_EQ(crl.status(),
@ -156,18 +181,18 @@ TEST(CrlProviderTest, InvalidFile) {
"Conversion from PEM string to X509 CRL failed."));
}
TEST(CrlProviderTest, StaticCrlProviderLookup) {
TEST_F(CrlProviderTest, StaticCrlProviderLookup) {
std::vector<std::string> crl_strings = {GetFileContents(kCrlPath.data())};
absl::StatusOr<std::shared_ptr<CrlProvider>> provider =
experimental::CreateStaticCrlProvider(crl_strings);
ASSERT_TRUE(provider.ok()) << provider.status();
CertificateInfoImpl cert(kCrlIssuer);
CertificateInfoImpl cert(base_crl_issuer_);
auto crl = (*provider)->GetCrl(cert);
ASSERT_NE(crl, nullptr);
EXPECT_EQ(crl->Issuer(), kCrlIssuer);
EXPECT_EQ(crl->Issuer(), base_crl_issuer_);
}
TEST(CrlProviderTest, StaticCrlProviderLookupIssuerNotFound) {
TEST_F(CrlProviderTest, StaticCrlProviderLookupIssuerNotFound) {
std::vector<std::string> crl_strings = {GetFileContents(kCrlPath.data())};
absl::StatusOr<std::shared_ptr<CrlProvider>> provider =
experimental::CreateStaticCrlProvider(crl_strings);
@ -181,14 +206,14 @@ TEST_F(DirectoryReloaderCrlProviderTest, CrlLookupGood) {
auto provider =
CreateCrlProvider(kCrlDirectory, std::chrono::seconds(60), nullptr);
ASSERT_TRUE(provider.ok()) << provider.status();
CertificateInfoImpl cert(kCrlIssuer);
CertificateInfoImpl cert(base_crl_issuer_);
auto crl = (*provider)->GetCrl(cert);
ASSERT_NE(crl, nullptr);
EXPECT_EQ(crl->Issuer(), kCrlIssuer);
CertificateInfoImpl intermediate(kCrlIntermediateIssuer);
EXPECT_EQ(crl->Issuer(), base_crl_issuer_);
CertificateInfoImpl intermediate(intermediate_crl_issuer_);
auto intermediate_crl = (*provider)->GetCrl(intermediate);
ASSERT_NE(intermediate_crl, nullptr);
EXPECT_EQ(intermediate_crl->Issuer(), kCrlIntermediateIssuer);
EXPECT_EQ(intermediate_crl->Issuer(), intermediate_crl_issuer_);
}
TEST_F(DirectoryReloaderCrlProviderTest, CrlLookupMissingIssuer) {
@ -204,7 +229,7 @@ TEST_F(DirectoryReloaderCrlProviderTest, ReloadsAndDeletes) {
const std::chrono::seconds kRefreshDuration(60);
auto provider = CreateCrlProvider(kRefreshDuration, nullptr);
ASSERT_TRUE(provider.ok()) << provider.status();
CertificateInfoImpl cert(kCrlIssuer);
CertificateInfoImpl cert(base_crl_issuer_);
auto should_be_no_crl = (*provider)->GetCrl(cert);
ASSERT_EQ(should_be_no_crl, nullptr);
// Give the provider files to find in the directory
@ -212,7 +237,7 @@ TEST_F(DirectoryReloaderCrlProviderTest, ReloadsAndDeletes) {
event_engine_->TickForDuration(kRefreshDuration);
auto crl = (*provider)->GetCrl(cert);
ASSERT_NE(crl, nullptr);
EXPECT_EQ(crl->Issuer(), kCrlIssuer);
EXPECT_EQ(crl->Issuer(), base_crl_issuer_);
// Now we won't see any files in our directory
directory_reader_->SetFilesInDirectory({});
event_engine_->TickForDuration(kRefreshDuration);
@ -229,10 +254,10 @@ TEST_F(DirectoryReloaderCrlProviderTest, WithCorruption) {
auto provider =
CreateCrlProvider(kRefreshDuration, std::move(reload_error_callback));
ASSERT_TRUE(provider.ok()) << provider.status();
CertificateInfoImpl cert(kCrlIssuer);
CertificateInfoImpl cert(base_crl_issuer_);
auto crl = (*provider)->GetCrl(cert);
ASSERT_NE(crl, nullptr);
EXPECT_EQ(crl->Issuer(), kCrlIssuer);
EXPECT_EQ(crl->Issuer(), base_crl_issuer_);
EXPECT_EQ(reload_errors.size(), 0);
// Point the provider at a non-crl file so loading fails
// Should result in the CRL Reloader keeping the old CRL data
@ -240,7 +265,7 @@ TEST_F(DirectoryReloaderCrlProviderTest, WithCorruption) {
event_engine_->TickForDuration(kRefreshDuration);
auto crl_post_update = (*provider)->GetCrl(cert);
ASSERT_NE(crl_post_update, nullptr);
EXPECT_EQ(crl_post_update->Issuer(), kCrlIssuer);
EXPECT_EQ(crl_post_update->Issuer(), base_crl_issuer_);
EXPECT_EQ(reload_errors.size(), 1);
}

@ -64,12 +64,23 @@ grpc_cc_test(
grpc_cc_test(
name = "ssl_transport_security_utils_test",
srcs = ["ssl_transport_security_utils_test.cc"],
data = [
"//test/core/tsi/test_creds/crl_data:ca.pem",
"//test/core/tsi/test_creds/crl_data:evil_ca.pem",
"//test/core/tsi/test_creds/crl_data:intermediate_ca.pem",
"//test/core/tsi/test_creds/crl_data:leaf_signed_by_intermediate.pem",
"//test/core/tsi/test_creds/crl_data/crls:current.crl",
"//test/core/tsi/test_creds/crl_data/crls:intermediate.crl",
"//test/core/tsi/test_creds/crl_data/crls:invalid_content.crl",
"//test/core/tsi/test_creds/crl_data/crls:invalid_signature.crl",
],
external_deps = ["gtest"],
language = "C++",
tags = ["no_windows"],
deps = [
"//:gpr",
"//:grpc",
"//test/core/tsi:transport_security_test_lib",
"//test/core/util:grpc_test_util",
],
)

@ -25,6 +25,7 @@
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
@ -32,13 +33,30 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "src/core/lib/gprpp/load_file.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/tsi/transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
#include "test/core/tsi/transport_security_test_lib.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
const char* kValidCrl = "test/core/tsi/test_creds/crl_data/crls/current.crl";
const char* kCrlIssuer = "test/core/tsi/test_creds/crl_data/ca.pem";
const char* kModifiedSignature =
"test/core/tsi/test_creds/crl_data/crls/invalid_signature.crl";
const char* kModifiedContent =
"test/core/tsi/test_creds/crl_data/crls/invalid_content.crl";
const char* kIntermediateCrl =
"test/core/tsi/test_creds/crl_data/crls/intermediate.crl";
const char* kIntermediateCrlIssuer =
"test/core/tsi/test_creds/crl_data/intermediate_ca.pem";
const char* kLeafCert =
"test/core/tsi/test_creds/crl_data/leaf_signed_by_intermediate.pem";
const char* kEvilCa = "test/core/tsi/test_creds/crl_data/evil_ca.pem";
using ::testing::ContainerEq;
using ::testing::NotNull;
using ::testing::TestWithParam;
@ -316,8 +334,8 @@ TEST_P(FlowTest,
&protected_output_frames_size),
tsi_result::TSI_OK);
// If |GetParam().plaintext_size| is larger than the inner client_buffer size
// (kMaxPlaintextBytesPerTlsRecord), then |Protect| will copy up to
// If |GetParam().plaintext_size| is larger than the inner client_buffer
// size (kMaxPlaintextBytesPerTlsRecord), then |Protect| will copy up to
// |kMaxPlaintextBytesPerTlsRecord| bytes and output the protected
// frame. Otherwise we need to manually flush the copied data in order
// to get the protected frame.
@ -378,8 +396,8 @@ TEST_P(FlowTest,
&protected_output_frames_size),
tsi_result::TSI_OK);
// If |GetParam().plaintext_size| is larger than the inner server_buffer size
// (kMaxPlaintextBytesPerTlsRecord), then |Protect| will copy up to
// If |GetParam().plaintext_size| is larger than the inner server_buffer
// size (kMaxPlaintextBytesPerTlsRecord), then |Protect| will copy up to
// |kMaxPlaintextBytesPerTlsRecord| bytes and output the protected
// frame. Otherwise we need to manually flush the copied data in order
// to get the protected frame.
@ -429,6 +447,188 @@ INSTANTIATE_TEST_SUITE_P(FrameProtectorUtil, FlowTest,
#endif // OPENSSL_IS_BORINGSSL
class CrlUtils : public ::testing::Test {
public:
static void SetUpTestSuite() {
#if OPENSSL_VERSION_NUMBER >= 0x10100000
OPENSSL_init_ssl(/*opts=*/0, /*settings=*/nullptr);
#else
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
#endif
}
void SetUp() override {
absl::StatusOr<Slice> root_crl = LoadFile(kValidCrl, false);
ASSERT_EQ(root_crl.status(), absl::OkStatus()) << root_crl.status();
root_crl_ = ReadCrl(root_crl->as_string_view());
absl::StatusOr<Slice> intermediate_crl = LoadFile(kIntermediateCrl, false);
ASSERT_EQ(intermediate_crl.status(), absl::OkStatus())
<< intermediate_crl.status();
intermediate_crl_ = ReadCrl(intermediate_crl->as_string_view());
absl::StatusOr<Slice> invalid_signature_crl =
LoadFile(kModifiedSignature, false);
ASSERT_EQ(invalid_signature_crl.status(), absl::OkStatus())
<< invalid_signature_crl.status();
invalid_signature_crl_ = ReadCrl(invalid_signature_crl->as_string_view());
absl::StatusOr<Slice> root_ca = LoadFile(kCrlIssuer, false);
ASSERT_EQ(root_ca.status(), absl::OkStatus());
root_ca_ = ReadPemCert(root_ca->as_string_view());
absl::StatusOr<Slice> intermediate_ca =
LoadFile(kIntermediateCrlIssuer, false);
ASSERT_EQ(intermediate_ca.status(), absl::OkStatus());
intermediate_ca_ = ReadPemCert(intermediate_ca->as_string_view());
absl::StatusOr<Slice> leaf_cert = LoadFile(kLeafCert, false);
ASSERT_EQ(leaf_cert.status(), absl::OkStatus());
leaf_cert_ = ReadPemCert(leaf_cert->as_string_view());
absl::StatusOr<Slice> evil_ca = LoadFile(kEvilCa, false);
ASSERT_EQ(evil_ca.status(), absl::OkStatus());
evil_ca_ = ReadPemCert(evil_ca->as_string_view());
}
void TearDown() override {
X509_CRL_free(root_crl_);
X509_CRL_free(intermediate_crl_);
X509_CRL_free(invalid_signature_crl_);
X509_free(root_ca_);
X509_free(intermediate_ca_);
X509_free(leaf_cert_);
X509_free(evil_ca_);
}
protected:
X509_CRL* root_crl_;
X509_CRL* intermediate_crl_;
X509_CRL* invalid_signature_crl_;
X509* root_ca_;
X509* intermediate_ca_;
X509* leaf_cert_;
X509* evil_ca_;
};
TEST_F(CrlUtils, VerifySignatureValid) {
EXPECT_TRUE(VerifyCrlSignature(root_crl_, root_ca_));
}
TEST_F(CrlUtils, VerifySignatureIntermediateValid) {
EXPECT_TRUE(VerifyCrlSignature(intermediate_crl_, intermediate_ca_));
}
TEST_F(CrlUtils, VerifySignatureModifiedSignature) {
EXPECT_FALSE(VerifyCrlSignature(invalid_signature_crl_, root_ca_));
}
TEST_F(CrlUtils, VerifySignatureModifiedContent) {
absl::StatusOr<Slice> crl_slice = LoadFile(kModifiedContent, false);
ASSERT_EQ(crl_slice.status(), absl::OkStatus()) << crl_slice.status();
X509_CRL* crl = ReadCrl(crl_slice->as_string_view());
EXPECT_EQ(crl, nullptr);
}
TEST_F(CrlUtils, VerifySignatureWrongIssuer) {
EXPECT_FALSE(VerifyCrlSignature(root_crl_, intermediate_ca_));
}
TEST_F(CrlUtils, VerifySignatureWrongIssuer2) {
EXPECT_FALSE(VerifyCrlSignature(intermediate_crl_, root_ca_));
}
TEST_F(CrlUtils, VerifySignatureNullCrl) {
EXPECT_FALSE(VerifyCrlSignature(nullptr, root_ca_));
}
TEST_F(CrlUtils, VerifySignatureNullCert) {
EXPECT_FALSE(VerifyCrlSignature(intermediate_crl_, nullptr));
}
TEST_F(CrlUtils, VerifySignatureNullCrlAndCert) {
EXPECT_FALSE(VerifyCrlSignature(nullptr, nullptr));
}
TEST_F(CrlUtils, VerifyIssuerNamesMatch) {
EXPECT_TRUE(VerifyCrlCertIssuerNamesMatch(root_crl_, root_ca_));
}
TEST_F(CrlUtils, VerifyIssuerNamesDontMatch) {
EXPECT_FALSE(VerifyCrlCertIssuerNamesMatch(root_crl_, leaf_cert_));
}
TEST_F(CrlUtils, DuplicatedIssuerNamePassesButSignatureCheckFails) {
// The issuer names will match, but it should fail a signature check
EXPECT_TRUE(VerifyCrlCertIssuerNamesMatch(root_crl_, evil_ca_));
EXPECT_FALSE(VerifyCrlSignature(root_crl_, evil_ca_));
}
TEST_F(CrlUtils, VerifyIssuerNameNullCrl) {
EXPECT_FALSE(VerifyCrlCertIssuerNamesMatch(nullptr, root_ca_));
}
TEST_F(CrlUtils, VerifyIssuerNameNullCert) {
EXPECT_FALSE(VerifyCrlCertIssuerNamesMatch(intermediate_crl_, nullptr));
}
TEST_F(CrlUtils, VerifyIssuerNameNullCrlAndCert) {
EXPECT_FALSE(VerifyCrlCertIssuerNamesMatch(nullptr, nullptr));
}
TEST_F(CrlUtils, HasCrlSignBitExists) { EXPECT_TRUE(HasCrlSignBit(root_ca_)); }
TEST_F(CrlUtils, HasCrlSignBitMissing) {
EXPECT_FALSE(HasCrlSignBit(leaf_cert_));
}
TEST_F(CrlUtils, HasCrlSignBitNullCert) {
EXPECT_FALSE(HasCrlSignBit(nullptr));
}
TEST_F(CrlUtils, IssuerFromIntermediateCert) {
auto issuer = IssuerFromCert(intermediate_ca_);
// Build the known name for comparison
unsigned char* buf = nullptr;
X509_NAME* expected_issuer_name = X509_NAME_new();
ASSERT_TRUE(
X509_NAME_add_entry_by_txt(expected_issuer_name, "C", MBSTRING_ASC,
(const unsigned char*)"AU", -1, -1, 0));
ASSERT_TRUE(X509_NAME_add_entry_by_txt(
expected_issuer_name, "ST", MBSTRING_ASC,
(const unsigned char*)"Some-State", -1, -1, 0));
ASSERT_TRUE(X509_NAME_add_entry_by_txt(
expected_issuer_name, "O", MBSTRING_ASC,
(const unsigned char*)"Internet Widgits Pty Ltd", -1, -1, 0));
ASSERT_TRUE(
X509_NAME_add_entry_by_txt(expected_issuer_name, "CN", MBSTRING_ASC,
(const unsigned char*)"testca", -1, -1, 0));
int len = i2d_X509_NAME(expected_issuer_name, &buf);
std::string expected_issuer_name_der(reinterpret_cast<char const*>(buf), len);
OPENSSL_free(buf);
X509_NAME_free(expected_issuer_name);
ASSERT_EQ(issuer.status(), absl::OkStatus());
EXPECT_EQ(*issuer, expected_issuer_name_der);
}
TEST_F(CrlUtils, IssuerFromLeaf) {
auto issuer = IssuerFromCert(leaf_cert_);
// Build the known name for comparison
unsigned char* buf = nullptr;
X509_NAME* expected_issuer_name = X509_NAME_new();
ASSERT_TRUE(X509_NAME_add_entry_by_txt(
expected_issuer_name, "CN", MBSTRING_ASC,
(const unsigned char*)"intermediatecert.example.com", -1, -1, 0));
int len = i2d_X509_NAME(expected_issuer_name, &buf);
std::string expected_issuer_name_der(reinterpret_cast<char const*>(buf), len);
OPENSSL_free(buf);
X509_NAME_free(expected_issuer_name);
ASSERT_EQ(issuer.status(), absl::OkStatus());
EXPECT_EQ(*issuer, expected_issuer_name_der);
}
TEST_F(CrlUtils, IssuerFromCertNull) {
auto issuer = IssuerFromCert(nullptr);
EXPECT_EQ(issuer.status().code(), absl::StatusCode::kInvalidArgument);
}
} // namespace testing
} // namespace grpc_core

@ -25,4 +25,5 @@ exports_files([
"leaf_and_intermediate_chain.pem",
"intermediate_ca.key",
"intermediate_ca.pem",
"evil_ca.pem",
])

@ -46,6 +46,11 @@ Generate a chain with a leaf cert signed by an intermediate CA and revoke the in
Run `intermediate_gen.sh` from the `test/core/tsi/test_creds/crl_data` directory
Generate a CA with the same issuer name but a different public key than the base CA
----------------------------------------------------------------------------
Run `evil_ca_gen.sh` from the `test/core/tsi/test_creds/crl_data` directory
Clean up:
---------

@ -19,4 +19,6 @@ exports_files([
"b9322cac.r0",
"current.crl",
"intermediate.crl",
"invalid_signature.crl",
"invalid_content.crl",
])

@ -0,0 +1,15 @@
-----BEGIN X509 CRL-----
AIICUDCCATgCAQEwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDEPMA0GA1UEAwwGdGVzdGNhFw0yMzAzMDMxODA2NDNaFw0zMzAyMjgxODA2NDNa
MIGcMCUCFEpMyQOrk+uXDu20PhHwDJeua83mFw0yMzAzMDMxNjU5NTNaMCUCFEpM
yQOrk+uXDu20PhHwDJeua83nFw0yMzAzMDMxNzMxNDBaMCUCFEpMyQOrk+uXDu20
PhHwDJeua83xFw0yMzAzMDMxODA2NDNaMCUCFFIgumScY9chZ0u8tUhjsOUh38hB
Fw0yMjAyMDQyMjExMTFaoA8wDTALBgNVHRQEBAICEAgwDQYJKoZIhvcNAQELBQAD
ggEBADohIZwm/gWLIc2yFJJbKzkdRmOq1s/MqnJxi5NutNumXTIPrZJqGzk8O4U6
VasicIB2YD0o3arzUxCDyHv7VyJI7SVS0lqlmOxoOEOv2+CB6MxAOdKItkzbVVxu
0erx5HcKAGa7ZIAeekX1F1DcAgpN5Gt5uGhkMw3ObTCpEFRw+ZKET3WFQ6bG4AJ6
GwOnNYG1LjaNigxG/k4K7A+grs/XnsNcpULbCROl7Qw4kyf1esrjS9utEO0YQQz4
LgBTPZzQHlsirmxp+e5WR8LiDsKmbmAaBL+gV1Bkjj73c4pNJvoV/V1Ubdv0LCvH
DjrJtp10F0RGMRm6m9OuZYUSFzs=
-----END X509 CRL-----

@ -0,0 +1,15 @@
-----BEGIN X509 CRL-----
MIICUDCCATgCAQEwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDEPMA0GA1UEAwwGdGVzdGNhFw0yMzAzMDMxODA2NDNaFw0zMzAyMjgxODA2NDNa
MIGcMCUCFEpMyQOrk+uXDu20PhHwDJeua83mFw0yMzAzMDMxNjU5NTNaMCUCFEpM
yQOrk+uXDu20PhHwDJeua83nFw0yMzAzMDMxNzMxNDBaMCUCFEpMyQOrk+uXDu20
PhHwDJeua83xFw0yMzAzMDMxODA2NDNaMCUCFFIgumScY9chZ0u8tUhjsOUh38hB
Fw0yMjAyMDQyMjExMTFaoA8wDTALBgNVHRQEBAICEAgwDQYJKoZIhvcNAQELBQAD
ggEBADohIZwm/gWLIc2yFJJbKzkdRmOq1s/MqnJxi5NutNumXTIPrZJqGzk8O4U6
VasicIB2YD0o3arzUxCDyHv7VyJI7SVS0lqlmOxoOEOv2+CB6MxAOdKItkzbVVxu
0erx5HcKAGa7ZIAeekX1F1DcAgpN5Gt5uGhkMw3ObTCpEFRw+ZKET3WFQ6bG4AJ6
GwOnNYG1LjaNigxG/k4K7A+grs/XnsNcpULbCROl7Qw4kyf1esrjS9utEO0YQQz4
LgBTPZzQHlsirmxp+e5WR8LiDsKmbmAaBL+gV1Bkjj73c4pNJvoV/V1Ubdv0LCvH
DjrJtp10F0RGMRm6m9OuZYUSFza=
-----END X509 CRL-----

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7RwHo8bWaioeI
oqq4qRkiRfqAl/XlaRCyygkMtkjuOy0LA42+LFXXNvDD8eVvVd3615Qopm0XzABd
iz2QiJBZH9qvvmZFg7vG4rbNMCHIN+0YYIOp5tJuyBUVhZ+/f/jZ+LoJeZgTRngQ
tMUmhs7kn4ttT+DC7ZHKhPf5vUokSPG4N2tBx21y2BzRup36q09vfvZeVEe5YxAM
KGWEOcCY/S5vTVeEJCqP2OfMmskIHq2cYWr6ZJzBpdhJXX6rTDWYlCzX49mzPrn6
povhA/bENv9Gy1OHqPKt+EWEJCaurerkFwF74OG9zp/jCKZJTVkyxnCYjT2rYiDX
gWvNwdeHAgMBAAECggEADyya44Mzj0Y6jXV8tsIA0YLxCrAFZ7q3ydIj9z3ih+cP
PcK3yUPHYCJJUjR3PipWIP03Dy949xd7pMNjpXfjQPgbRz0lWpboxUiDvk7FlfcD
b4O2d12cCbI4Px+uHh1M48B1tnnTOtCYFDvJc6yITARUuZ03cs6UDwrvcB1dygsO
2sZLUOkWQb2DCMq86bxmkHvjuh3gj/CMTJv0Kprlo3YcKNgCwiNygEzlusyIcwpf
dU/SNoWcxY+F0F6wFC0uj75wWqDB6bmfCpY8Bb3Ey7TgWDTWjsB/NQsWbSxZ9o5i
qjQ6WSLKpLLLB/8dXxhk3Nz9tfonavBpLB+4fNpFFQKBgQDi61A3/U88iEo+sxMm
L3i0OS9g/mAnYQ7zYjq42eVyDTfa+eBck1Jmp1KEblfy7Eo3iyApNFoIzFz8va8N
tPNFK/K4mrf1aiFOk0SnvCstW8SBS99hBHXqrMnXrRh+L/OafM4sj88P4RbZxcIs
9RNiDIqcXAPDVU5aHIhs7CFzYwKBgQDTRyOR9PoTQnu0HV0ODDNzmP1eRWrXZ62N
khe9bm0TIG25Q1wsoR6MT5fxZlTe62FH7A5QgEheRtMctr+XGC2H+3N3MUxsTy37
knPFiDl6Gs5DqKroewiDNbkziMOgctG/z6ORPiGghTRsn6y5dBaMstfvgip8fj5z
ytzgSfiujQKBgHZraOSfK++iDGTmHRMraOlcgm4ysck7LIs08wIurD+1yDVde4m0
VCdAIJ792qXqS9zqnPED4gx/YfN/pdAYY2/wvG08SM4pAZK45fZHC51TK5xyFPPT
WRoL7BXCvmpz6cPwZ8P3lI5r3/nr6yZ9Cw17EAcDOe+BIC+EfmmhXN+TAoGBAIp0
oDbSV9+vPen3JDhEfqNOqxvQWgf3haC1EKGvcAOMyNsT7Z/BpodE0cn8ybmcfw/m
/ip7JvHBcC/tAvk9evkWK8D8qZyA9x1aCEx2zVPbpThpnDbmCdoSpt/CzJClLheJ
NyPDl73eDVDyAvs1vGFQAnqOztDu2nZ/huflEfcxAoGAbLUQV5PjqJrsIosEMXsv
qOzQZ5BBEk/jo9zqYSNXWVs0I9Invj5iAYewoM5qn9DFQ3q3O/mPHxF6HT7JHfjn
T8wdOTQk5L1yaaSFsiti3C3AQ2zShT1k6m3V+mf0iWJw878LCURQQFNIHu7zVdXy
4xwQpVw2CN7iufRYN7kOcDo=
-----END PRIVATE KEY-----

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDeTCCAmGgAwIBAgIUULA9nt1NB3W1i4RevrKeRQQLkaIwDQYJKoZIhvcNAQEL
BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTI0
MDEyMjIxNDAyMFoXDTM0MDExOTIxNDAyMFowVjELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDEPMA0GA1UEAwwGdGVzdGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAu0cB6PG1moqHiKKquKkZIkX6gJf15WkQssoJDLZI7jstCwONvixV1zbww/Hl
b1Xd+teUKKZtF8wAXYs9kIiQWR/ar75mRYO7xuK2zTAhyDftGGCDqebSbsgVFYWf
v3/42fi6CXmYE0Z4ELTFJobO5J+LbU/gwu2RyoT3+b1KJEjxuDdrQcdtctgc0bqd
+qtPb372XlRHuWMQDChlhDnAmP0ub01XhCQqj9jnzJrJCB6tnGFq+mScwaXYSV1+
q0w1mJQs1+PZsz65+qaL4QP2xDb/RstTh6jyrfhFhCQmrq3q5BcBe+Dhvc6f4wim
SU1ZMsZwmI09q2Ig14FrzcHXhwIDAQABoz8wPTAMBgNVHRMEBTADAQH/MA4GA1Ud
DwEB/wQEAwIBBjAdBgNVHQ4EFgQUjcQvfJ6kAUgljgToPpQ0DmCW0Q8wDQYJKoZI
hvcNAQELBQADggEBALLNhOYqlhOcCsTD1SPfm9MAjfpV1EjSjDCpIfwCk5gI2CUX
g7MyUzn2gQJUiYx74BKmjv6W/sLzNxqR0wZQUr4d/7HX+Lm0xCCYdIUELEM8lZ30
maBJ599cQnLXDB1ZFEekj3DMM6jL7OQnBaDs5jW4GcDcuwd5cgXfgIaZVjBVJ11Y
CFAhIuh5CM8xhqxWYWY+h0VLU64s8WCNrBEy1OU5KpQRfpd4cvpoWn7E1SfhK1Iq
Bp+1k4oDBpGGw4NLXI3i1aU8x1+KoXxNRg5dOED0OLgppvaWB2yIpqBlcZDaNpq4
P+WFGBiSUpWU5yYwCDvQAgTWtWkmyflVwslHaGs=
-----END CERTIFICATE-----

@ -0,0 +1,18 @@
#!/bin/bash
# Copyright 2024 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Generates a CA with the same issuer name as the good CA in this directory
openssl req -x509 -new -newkey rsa:2048 -nodes -keyout evil_ca.key -out evil_ca.pem \
-config ca-openssl.cnf -days 3650 -extensions v3_req

@ -62,11 +62,9 @@ cp "./intermediate_ca/intermediate.crl" ./crls
cp current.crl ./crls/
openssl rehash ./crls/
mkdir crls_missing_intermediate
cp current.crl ./crls_missing_intermediate/
openssl rehash ./crls_missing_intermediate/
mkdir crls_missing_root
cp intermediate.crl ./crls_missing_root/
openssl rehash ./crls_missing_root/

@ -762,3 +762,27 @@ std::string GenerateSelfSignedCertificate(
BN_free(n);
return pem;
}
X509* ReadPemCert(absl::string_view pem_cert) {
BIO* cert_bio =
BIO_new_mem_buf(pem_cert.data(), static_cast<int>(pem_cert.size()));
// Errors on BIO
if (cert_bio == nullptr) {
return nullptr;
}
X509* cert = PEM_read_bio_X509(cert_bio, nullptr, nullptr, nullptr);
BIO_free(cert_bio);
return cert;
}
X509_CRL* ReadCrl(absl::string_view crl_pem) {
BIO* crl_bio =
BIO_new_mem_buf(crl_pem.data(), static_cast<int>(crl_pem.size()));
// Errors on BIO
if (crl_bio == nullptr) {
return nullptr;
}
X509_CRL* crl = PEM_read_bio_X509_CRL(crl_bio, nullptr, nullptr, nullptr);
BIO_free(crl_bio);
return crl;
}

@ -19,6 +19,8 @@
#ifndef GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H
#define GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H
#include <openssl/x509v3.h>
#include <grpc/support/sync.h>
#include "src/core/tsi/transport_security_interface.h"
@ -238,4 +240,10 @@ struct SelfSignedCertificateOptions {
std::string GenerateSelfSignedCertificate(
const SelfSignedCertificateOptions& options);
// Returns the OpenSSL representation of a PEM cert.
X509* ReadPemCert(absl::string_view pem_cert);
// Returns the OpenSSL representation of a CRL.
X509_CRL* ReadCrl(absl::string_view crl_pem);
#endif // GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H

@ -63,7 +63,6 @@ grpc_cc_library(
"histogram.cc",
"mock_endpoint.cc",
"parse_hexstring.cc",
"passthru_endpoint.cc",
"resolve_localhost_ip46.cc",
"slice_splitter.cc",
"tracer_util.cc",
@ -77,7 +76,6 @@ grpc_cc_library(
"mock_authorization_endpoint.h",
"mock_endpoint.h",
"parse_hexstring.h",
"passthru_endpoint.h",
"resolve_localhost_ip46.h",
"slice_splitter.h",
"tracer_util.h",

@ -1,525 +0,0 @@
//
//
// Copyright 2016 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#include "test/core/util/passthru_endpoint.h"
#include <string.h>
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include <grpc/event_engine/event_engine.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr_fwd.h"
using ::grpc_event_engine::experimental::EventEngine;
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
typedef struct passthru_endpoint passthru_endpoint;
typedef struct {
bool is_armed;
grpc_endpoint* ep;
grpc_slice_buffer* slices;
grpc_closure* cb;
} pending_op;
typedef struct {
absl::optional<EventEngine::TaskHandle> timer_handle;
uint64_t allowed_write_bytes;
uint64_t allowed_read_bytes;
std::vector<grpc_passthru_endpoint_channel_action> actions;
std::function<void()> on_complete;
} grpc_passthru_endpoint_channel_effects;
typedef struct {
grpc_endpoint base;
passthru_endpoint* parent;
grpc_slice_buffer read_buffer;
grpc_slice_buffer write_buffer;
grpc_slice_buffer* on_read_out;
grpc_closure* on_read;
pending_op pending_read_op;
pending_op pending_write_op;
uint64_t bytes_read_so_far;
uint64_t bytes_written_so_far;
} half;
struct passthru_endpoint {
gpr_mu mu;
int halves;
grpc_passthru_endpoint_stats* stats;
grpc_passthru_endpoint_channel_effects* channel_effects;
bool simulate_channel_actions;
bool shutdown;
half client;
half server;
};
static void do_pending_read_op_locked(half* m, grpc_error_handle error) {
GPR_ASSERT(m->pending_read_op.is_armed);
GPR_ASSERT(m->bytes_read_so_far <=
m->parent->channel_effects->allowed_read_bytes);
if (m->parent->shutdown) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, m->pending_read_op.cb,
GRPC_ERROR_CREATE("Already shutdown"));
// Move any pending data into pending_read_op.slices so that it may be
// free'ed by the executing callback.
grpc_slice_buffer_move_into(&m->read_buffer, m->pending_read_op.slices);
m->pending_read_op.is_armed = false;
return;
}
if (m->bytes_read_so_far == m->parent->channel_effects->allowed_read_bytes) {
// Keep it in pending state.
return;
}
// This delayed processing should only be invoked when read_buffer has
// something in it.
GPR_ASSERT(m->read_buffer.count > 0);
uint64_t readable_length = std::min<uint64_t>(
m->read_buffer.length,
m->parent->channel_effects->allowed_read_bytes - m->bytes_read_so_far);
GPR_ASSERT(readable_length > 0);
grpc_slice_buffer_move_first(&m->read_buffer, readable_length,
m->pending_read_op.slices);
grpc_core::ExecCtx::Run(DEBUG_LOCATION, m->pending_read_op.cb, error);
if (m->parent->simulate_channel_actions) {
m->bytes_read_so_far += readable_length;
}
m->pending_read_op.is_armed = false;
}
static void me_read(grpc_endpoint* ep, grpc_slice_buffer* slices,
grpc_closure* cb, bool /*urgent*/,
int /*min_progress_size*/) {
half* m = reinterpret_cast<half*>(ep);
gpr_mu_lock(&m->parent->mu);
if (m->parent->shutdown) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb,
GRPC_ERROR_CREATE("Already shutdown"));
} else if (m->read_buffer.count > 0) {
GPR_ASSERT(!m->pending_read_op.is_armed);
GPR_ASSERT(!m->on_read);
m->pending_read_op.is_armed = true;
m->pending_read_op.cb = cb;
m->pending_read_op.ep = ep;
m->pending_read_op.slices = slices;
do_pending_read_op_locked(m, absl::OkStatus());
} else {
GPR_ASSERT(!m->pending_read_op.is_armed);
m->on_read = cb;
m->on_read_out = slices;
}
gpr_mu_unlock(&m->parent->mu);
}
// Copy src slice and split the copy at n bytes into two separate slices
void grpc_slice_copy_split(grpc_slice src, uint64_t n, grpc_slice& split1,
grpc_slice& split2) {
GPR_ASSERT(n <= GRPC_SLICE_LENGTH(src));
if (n == GRPC_SLICE_LENGTH(src)) {
split1 = grpc_slice_copy(src);
split2 = grpc_empty_slice();
return;
}
split1 = GRPC_SLICE_MALLOC(n);
memcpy(GRPC_SLICE_START_PTR(split1), GRPC_SLICE_START_PTR(src), n);
split2 = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(src) - n);
memcpy(GRPC_SLICE_START_PTR(split2), GRPC_SLICE_START_PTR(src) + n,
GRPC_SLICE_LENGTH(src) - n);
}
static half* other_half(half* h) {
if (h == &h->parent->client) return &h->parent->server;
return &h->parent->client;
}
static void do_pending_write_op_locked(half* m, grpc_error_handle error) {
GPR_ASSERT(m->pending_write_op.is_armed);
GPR_ASSERT(m->bytes_written_so_far <=
m->parent->channel_effects->allowed_write_bytes);
if (m->parent->shutdown) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, m->pending_write_op.cb,
GRPC_ERROR_CREATE("Already shutdown"));
m->pending_write_op.is_armed = false;
grpc_slice_buffer_reset_and_unref(m->pending_write_op.slices);
return;
}
if (m->bytes_written_so_far ==
m->parent->channel_effects->allowed_write_bytes) {
// Keep it in pending state.
return;
}
half* other = other_half(m);
uint64_t max_writable =
std::min<uint64_t>(m->pending_write_op.slices->length,
m->parent->channel_effects->allowed_write_bytes -
m->bytes_written_so_far);
uint64_t max_readable = other->parent->channel_effects->allowed_read_bytes -
other->bytes_read_so_far;
uint64_t immediate_bytes_read =
other->on_read != nullptr ? std::min<uint64_t>(max_readable, max_writable)
: 0;
GPR_ASSERT(max_writable > 0);
GPR_ASSERT(max_readable >= 0);
// At the end of this process, we should have written max_writable bytes;
if (m->parent->simulate_channel_actions) {
m->bytes_written_so_far += max_writable;
}
// Estimate if the original write would still be pending at the end of this
// process
bool would_write_be_pending =
max_writable < m->pending_write_op.slices->length;
if (!m->parent->simulate_channel_actions) {
GPR_ASSERT(!would_write_be_pending);
}
grpc_slice_buffer* slices = m->pending_write_op.slices;
grpc_slice_buffer* dest =
other->on_read != nullptr ? other->on_read_out : &other->read_buffer;
while (max_writable > 0) {
grpc_slice slice = grpc_slice_buffer_take_first(slices);
uint64_t slice_length = GRPC_SLICE_LENGTH(slice);
GPR_ASSERT(slice_length > 0);
grpc_slice split1, split2;
uint64_t split_length = 0;
if (slice_length <= max_readable) {
split_length = std::min<uint64_t>(slice_length, max_writable);
} else if (max_readable > 0) {
// slice_length > max_readable
split_length = std::min<uint64_t>(max_readable, max_writable);
} else {
// slice_length still > max_readable but max_readable is 0.
// In this case put the bytes into other->read_buffer. During a future
// read if max_readable still remains zero at the time of read, the
// pending read logic will kick in.
dest = &other->read_buffer;
split_length = std::min<uint64_t>(slice_length, max_writable);
}
grpc_slice_copy_split(slice, split_length, split1, split2);
grpc_slice_unref(slice);
// Write a copy of the slice to the destination to be read
grpc_slice_buffer_add_indexed(dest, split1);
// Re-insert split2 into source for next iteration.
if (GRPC_SLICE_LENGTH(split2) > 0) {
grpc_slice_buffer_undo_take_first(slices, split2);
} else {
grpc_slice_unref(split2);
}
if (max_readable > 0) {
GPR_ASSERT(max_readable >= static_cast<uint64_t>(split_length));
max_readable -= split_length;
}
GPR_ASSERT(max_writable >= static_cast<uint64_t>(split_length));
max_writable -= split_length;
}
if (immediate_bytes_read > 0) {
GPR_ASSERT(!other->pending_read_op.is_armed);
if (m->parent->simulate_channel_actions) {
other->bytes_read_so_far += immediate_bytes_read;
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION, other->on_read, error);
other->on_read = nullptr;
}
if (!would_write_be_pending) {
// No slices should be left
GPR_ASSERT(m->pending_write_op.slices->count == 0);
grpc_slice_buffer_reset_and_unref(m->pending_write_op.slices);
m->pending_write_op.is_armed = false;
grpc_core::ExecCtx::Run(DEBUG_LOCATION, m->pending_write_op.cb, error);
}
}
static void me_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
grpc_closure* cb, void* /*arg*/, int /*max_frame_size*/) {
half* m = reinterpret_cast<half*>(ep);
gpr_mu_lock(&m->parent->mu);
gpr_atm_full_fetch_add(&m->parent->stats->num_writes, (gpr_atm)1);
if (m->parent->shutdown) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb,
GRPC_ERROR_CREATE("Endpoint already shutdown"));
} else {
GPR_ASSERT(!m->pending_write_op.is_armed);
// Copy slices into m->pending_write_op.slices
m->pending_write_op.slices = &m->write_buffer;
GPR_ASSERT(m->pending_write_op.slices->count == 0);
for (int i = 0; i < static_cast<int>(slices->count); i++) {
if (GRPC_SLICE_LENGTH(slices->slices[i]) > 0) {
grpc_slice_buffer_add_indexed(m->pending_write_op.slices,
grpc_slice_copy(slices->slices[i]));
}
}
if (m->pending_write_op.slices->count > 0) {
m->pending_write_op.is_armed = true;
m->pending_write_op.cb = cb;
m->pending_write_op.ep = ep;
do_pending_write_op_locked(m, absl::OkStatus());
} else {
// There is nothing to write. Schedule callback to be run right away.
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, absl::OkStatus());
}
}
gpr_mu_unlock(&m->parent->mu);
}
void flush_pending_ops_locked(half* m, grpc_error_handle error) {
if (m->pending_read_op.is_armed) {
do_pending_read_op_locked(m, error);
}
if (m->pending_write_op.is_armed) {
do_pending_write_op_locked(m, error);
}
}
static void me_add_to_pollset(grpc_endpoint* /*ep*/,
grpc_pollset* /*pollset*/) {}
static void me_add_to_pollset_set(grpc_endpoint* /*ep*/,
grpc_pollset_set* /*pollset*/) {}
static void me_delete_from_pollset_set(grpc_endpoint* /*ep*/,
grpc_pollset_set* /*pollset*/) {}
static void shutdown_locked(half* m, grpc_error_handle why) {
m->parent->shutdown = true;
flush_pending_ops_locked(m, absl::OkStatus());
if (m->on_read) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, m->on_read,
GRPC_ERROR_CREATE_REFERENCING("Shutdown", &why, 1));
m->on_read = nullptr;
}
m = other_half(m);
flush_pending_ops_locked(m, absl::OkStatus());
if (m->on_read) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, m->on_read,
GRPC_ERROR_CREATE_REFERENCING("Shutdown", &why, 1));
m->on_read = nullptr;
}
}
static void me_shutdown(grpc_endpoint* ep, grpc_error_handle why) {
half* m = reinterpret_cast<half*>(ep);
gpr_mu_lock(&m->parent->mu);
shutdown_locked(m, why);
gpr_mu_unlock(&m->parent->mu);
}
void grpc_passthru_endpoint_destroy(passthru_endpoint* p) {
gpr_mu_destroy(&p->mu);
grpc_passthru_endpoint_stats_destroy(p->stats);
delete p->channel_effects;
grpc_slice_buffer_destroy(&p->client.read_buffer);
grpc_slice_buffer_destroy(&p->server.read_buffer);
grpc_slice_buffer_destroy(&p->client.write_buffer);
grpc_slice_buffer_destroy(&p->server.write_buffer);
gpr_free(p);
}
static void do_next_sched_channel_action(void* arg, grpc_error_handle error);
static void me_destroy(grpc_endpoint* ep) {
passthru_endpoint* p = (reinterpret_cast<half*>(ep))->parent;
gpr_mu_lock(&p->mu);
if (0 == --p->halves && p->channel_effects->actions.empty()) {
// no pending channel actions exist
gpr_mu_unlock(&p->mu);
grpc_passthru_endpoint_destroy(p);
} else {
if (p->halves == 0 && p->simulate_channel_actions) {
if (p->channel_effects->timer_handle.has_value()) {
if (GetDefaultEventEngine()->Cancel(
*p->channel_effects->timer_handle)) {
gpr_mu_unlock(&p->mu);
// This will destroy the passthru endpoint so just return after that.
do_next_sched_channel_action(ep, absl::CancelledError());
return;
}
p->channel_effects->timer_handle.reset();
}
}
gpr_mu_unlock(&p->mu);
}
}
static absl::string_view me_get_peer(grpc_endpoint* ep) {
passthru_endpoint* p = (reinterpret_cast<half*>(ep))->parent;
return (reinterpret_cast<half*>(ep)) == &p->client
? "fake:mock_client_endpoint"
: "fake:mock_server_endpoint";
}
static absl::string_view me_get_local_address(grpc_endpoint* ep) {
passthru_endpoint* p = (reinterpret_cast<half*>(ep))->parent;
return (reinterpret_cast<half*>(ep)) == &p->client
? "fake:mock_client_endpoint"
: "fake:mock_server_endpoint";
}
static int me_get_fd(grpc_endpoint* /*ep*/) { return -1; }
static bool me_can_track_err(grpc_endpoint* /*ep*/) { return false; }
static const grpc_endpoint_vtable vtable = {
me_read,
me_write,
me_add_to_pollset,
me_add_to_pollset_set,
me_delete_from_pollset_set,
me_shutdown,
me_destroy,
me_get_peer,
me_get_local_address,
me_get_fd,
me_can_track_err,
};
static void half_init(half* m, passthru_endpoint* parent,
const char* half_name) {
m->base.vtable = &vtable;
m->parent = parent;
grpc_slice_buffer_init(&m->read_buffer);
grpc_slice_buffer_init(&m->write_buffer);
m->pending_write_op.slices = nullptr;
m->on_read = nullptr;
m->bytes_read_so_far = 0;
m->bytes_written_so_far = 0;
m->pending_write_op.is_armed = false;
m->pending_read_op.is_armed = false;
std::string name =
absl::StrFormat("passthru_endpoint_%s_%p", half_name, parent);
}
void grpc_passthru_endpoint_create(grpc_endpoint** client,
grpc_endpoint** server,
grpc_passthru_endpoint_stats* stats,
bool simulate_channel_actions) {
passthru_endpoint* m =
static_cast<passthru_endpoint*>(gpr_malloc(sizeof(*m)));
m->halves = 2;
m->shutdown = false;
if (stats == nullptr) {
m->stats = grpc_passthru_endpoint_stats_create();
} else {
gpr_ref(&stats->refs);
m->stats = stats;
}
m->channel_effects = new grpc_passthru_endpoint_channel_effects();
m->simulate_channel_actions = simulate_channel_actions;
if (!simulate_channel_actions) {
m->channel_effects->allowed_read_bytes = UINT64_MAX;
m->channel_effects->allowed_write_bytes = UINT64_MAX;
}
half_init(&m->client, m, "client");
half_init(&m->server, m, "server");
gpr_mu_init(&m->mu);
*client = &m->client.base;
*server = &m->server.base;
}
grpc_passthru_endpoint_stats* grpc_passthru_endpoint_stats_create() {
grpc_passthru_endpoint_stats* stats =
static_cast<grpc_passthru_endpoint_stats*>(
gpr_malloc(sizeof(grpc_passthru_endpoint_stats)));
memset(stats, 0, sizeof(*stats));
gpr_ref_init(&stats->refs, 1);
return stats;
}
void grpc_passthru_endpoint_stats_destroy(grpc_passthru_endpoint_stats* stats) {
if (gpr_unref(&stats->refs)) {
gpr_free(stats);
}
}
static void sched_next_channel_action_locked(half* m);
static void do_next_sched_channel_action(void* arg, grpc_error_handle error) {
half* m = reinterpret_cast<half*>(arg);
gpr_mu_lock(&m->parent->mu);
GPR_ASSERT(!m->parent->channel_effects->actions.empty());
if (m->parent->halves == 0) {
gpr_mu_unlock(&m->parent->mu);
grpc_passthru_endpoint_destroy(m->parent);
return;
}
auto curr_action = m->parent->channel_effects->actions[0];
m->parent->channel_effects->actions.erase(
m->parent->channel_effects->actions.begin());
m->parent->channel_effects->allowed_read_bytes +=
curr_action.add_n_readable_bytes;
m->parent->channel_effects->allowed_write_bytes +=
curr_action.add_n_writable_bytes;
flush_pending_ops_locked(m, error);
flush_pending_ops_locked(other_half(m), error);
sched_next_channel_action_locked(m);
gpr_mu_unlock(&m->parent->mu);
}
static void sched_next_channel_action_locked(half* m) {
if (m->parent->channel_effects->actions.empty()) {
grpc_error_handle err = GRPC_ERROR_CREATE("Channel actions complete");
shutdown_locked(m, err);
return;
}
m->parent->channel_effects->timer_handle = GetDefaultEventEngine()->RunAfter(
grpc_core::Duration::Milliseconds(
m->parent->channel_effects->actions[0].wait_ms),
[m] {
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
grpc_core::ExecCtx exec_ctx;
do_next_sched_channel_action(m, absl::OkStatus());
});
}
void start_scheduling_grpc_passthru_endpoint_channel_effects(
grpc_endpoint* ep,
const std::vector<grpc_passthru_endpoint_channel_action>& actions) {
half* m = reinterpret_cast<half*>(ep);
gpr_mu_lock(&m->parent->mu);
if (!m->parent->simulate_channel_actions || m->parent->shutdown) {
gpr_mu_unlock(&m->parent->mu);
return;
}
m->parent->channel_effects->actions = actions;
sched_next_channel_action_locked(m);
gpr_mu_unlock(&m->parent->mu);
}

@ -1,58 +0,0 @@
//
//
// Copyright 2016 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#ifndef GRPC_TEST_CORE_UTIL_PASSTHRU_ENDPOINT_H
#define GRPC_TEST_CORE_UTIL_PASSTHRU_ENDPOINT_H
#include <stdint.h>
#include <vector>
#include <grpc/support/atm.h>
#include <grpc/support/sync.h>
#include "src/core/lib/iomgr/endpoint.h"
// The struct is refcounted, always use grpc_passthru_endpoint_stats_create and
// grpc_passthru_endpoint_stats_destroy, rather then embedding it in your
// objects by value.
typedef struct {
gpr_refcount refs;
gpr_atm num_writes;
} grpc_passthru_endpoint_stats;
typedef struct {
uint64_t wait_ms;
uint64_t add_n_writable_bytes;
uint64_t add_n_readable_bytes;
} grpc_passthru_endpoint_channel_action;
void grpc_passthru_endpoint_create(grpc_endpoint** client,
grpc_endpoint** server,
grpc_passthru_endpoint_stats* stats,
bool simulate_channel_actions = false);
grpc_passthru_endpoint_stats* grpc_passthru_endpoint_stats_create();
void grpc_passthru_endpoint_stats_destroy(grpc_passthru_endpoint_stats* stats);
void start_scheduling_grpc_passthru_endpoint_channel_effects(
grpc_endpoint* ep,
const std::vector<grpc_passthru_endpoint_channel_action>& actions);
#endif // GRPC_TEST_CORE_UTIL_PASSTHRU_ENDPOINT_H

@ -13,8 +13,10 @@
// limitations under the License.
//
#include <algorithm>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include <gmock/gmock.h>
@ -24,9 +26,11 @@
#include "src/core/client_channel/backup_poller.h"
#include "src/core/lib/config/config_vars.h"
#include "src/proto/grpc/testing/xds/v3/listener.pb.h"
#include "test/core/util/resolve_localhost_ip46.h"
#include "test/core/util/scoped_env_var.h"
#include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
#include "test/cpp/end2end/xds/xds_server.h"
namespace grpc {
namespace testing {
@ -167,7 +171,21 @@ INSTANTIATE_TEST_SUITE_P(XdsTest, GlobalXdsClientTest,
XdsTestType::kBootstrapFromEnvVar)),
&XdsTestType::Name);
TEST_P(GlobalXdsClientTest, MultipleChannelsShareXdsClient) {
TEST_P(GlobalXdsClientTest, MultipleChannelsSameTargetShareXdsClient) {
CreateAndStartBackends(1);
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
WaitForAllBackends(DEBUG_LOCATION);
// Create second channel and tell it to connect to the same server.
auto channel2 = CreateChannel(/*failover_timeout_ms=*/0, kServerName);
channel2->GetState(/*try_to_connect=*/true);
ASSERT_TRUE(channel2->WaitForConnected(grpc_timeout_seconds_to_deadline(1)));
// Make sure there's only one client connected.
EXPECT_EQ(1UL, balancer_->ads_service()->clients().size());
}
TEST_P(GlobalXdsClientTest,
MultipleChannelsDifferentTargetDoNotShareXdsClient) {
CreateAndStartBackends(1);
const char* kNewServerName = "new-server.example.com";
Listener listener = default_listener_;
@ -181,8 +199,8 @@ TEST_P(GlobalXdsClientTest, MultipleChannelsShareXdsClient) {
auto channel2 = CreateChannel(/*failover_timeout_ms=*/0, kNewServerName);
channel2->GetState(/*try_to_connect=*/true);
ASSERT_TRUE(channel2->WaitForConnected(grpc_timeout_seconds_to_deadline(1)));
// Make sure there's only one client connected.
EXPECT_EQ(1UL, balancer_->ads_service()->clients().size());
// Make sure there are two clients connected.
EXPECT_EQ(2UL, balancer_->ads_service()->clients().size());
}
TEST_P(
@ -219,64 +237,62 @@ TEST_P(
}
// Tests that the NACK for multiple bad LDS resources includes both errors.
// This needs to be in GlobalXdsClientTest because the only way to request
// two LDS resources in the same XdsClient is for two channels to share
// the same XdsClient.
// This needs to use xDS server as this is the only scenario when XdsClient
// is shared.
TEST_P(GlobalXdsClientTest, MultipleBadLdsResources) {
CreateAndStartBackends(1);
constexpr char kServerName2[] = "server.other.com";
constexpr char kServerName3[] = "server.another.com";
auto listener = default_listener_;
listener.clear_api_listener();
balancer_->ads_service()->SetLdsResource(listener);
listener.set_name(kServerName2);
balancer_->ads_service()->SetLdsResource(listener);
listener = default_listener_;
listener.set_name(kServerName3);
SetListenerAndRouteConfiguration(balancer_.get(), listener,
default_route_config_);
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
CreateBackends(2, true);
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 2)}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
auto listener = default_server_listener_;
listener.clear_address();
listener.set_name(GetServerListenerName(backends_[0]->port()));
balancer_->ads_service()->SetLdsResource(listener);
backends_[0]->Start();
auto response_state = WaitForLdsNack(DEBUG_LOCATION);
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
EXPECT_EQ(response_state->error_message,
"xDS response validation errors: ["
"resource index 0: server.example.com: "
"INVALID_ARGUMENT: Listener has neither address nor ApiListener]");
// Need to create a second channel to subscribe to a second LDS resource.
auto channel2 = CreateChannel(0, kServerName2);
auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
{
ClientContext context;
EchoRequest request;
request.set_message(kRequestMessage);
EchoResponse response;
grpc::Status status = stub2->Echo(&context, request, &response);
EXPECT_FALSE(status.ok());
// Wait for second NACK to be reported to xDS server.
const auto response_state = WaitForLdsNack(DEBUG_LOCATION);
ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
EXPECT_EQ(
response_state->error_message,
"xDS response validation errors: ["
"resource index 0: server.other.com: "
"INVALID_ARGUMENT: Listener has neither address nor ApiListener; "
"resource index 1: server.example.com: "
"INVALID_ARGUMENT: Listener has neither address nor ApiListener]");
}
// Now start a new channel with a third server name, this one with a
// valid resource.
auto channel3 = CreateChannel(0, kServerName3);
auto stub3 = grpc::testing::EchoTestService::NewStub(channel3);
{
ClientContext context;
EchoRequest request;
request.set_message(kRequestMessage);
EchoResponse response;
grpc::Status status = stub3->Echo(&context, request, &response);
EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
<< " message=" << status.error_message();
}
EXPECT_EQ(
response_state->error_message,
absl::StrFormat(
"xDS response validation errors: ["
"resource index 0: "
"grpc/server?xds.resource.listening_address=127.0.0.1:%lu: "
"INVALID_ARGUMENT: Listener has neither address nor ApiListener]",
backends_[0]->port()));
listener = default_server_listener_;
listener.clear_address();
listener.set_name(GetServerListenerName(backends_[1]->port()));
balancer_->ads_service()->SetLdsResource(listener);
backends_[1]->Start();
constexpr absl::string_view kMessageFormat =
"xDS response validation errors: ["
"resource index 0: "
"grpc/server?xds.resource.listening_address=127.0.0.1:%d: "
"INVALID_ARGUMENT: Listener has neither address nor "
"ApiListener; "
"resource index 1: "
"grpc/server?xds.resource.listening_address=127.0.0.1:%d: "
"INVALID_ARGUMENT: Listener has neither address nor "
"ApiListener"
"]";
const std::string expected_message1 = absl::StrFormat(
kMessageFormat, backends_[0]->port(), backends_[1]->port());
const std::string expected_message2 = absl::StrFormat(
kMessageFormat, backends_[1]->port(), backends_[0]->port());
response_state = WaitForNack(
DEBUG_LOCATION, [&]() -> absl::optional<AdsServiceImpl::ResponseState> {
auto response = balancer_->ads_service()->lds_response_state();
if (response.has_value() &&
response->state == AdsServiceImpl::ResponseState::NACKED) {
if (response->error_message == expected_message1 ||
response->error_message == expected_message2) {
return response;
}
gpr_log(GPR_INFO, "non-matching NACK message: %s",
response->error_message.c_str());
}
return absl::nullopt;
});
EXPECT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
}
// Tests that we don't trigger does-not-exist callbacks for a resource

@ -22,6 +22,7 @@
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/strip.h"
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
@ -344,7 +345,7 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpVanilla) {
// Fetches the client config
auto csds_response = FetchCsdsResponse();
gpr_log(GPR_INFO, "xDS config dump: %s", csds_response.DebugString().c_str());
EXPECT_EQ(1, csds_response.config_size());
ASSERT_EQ(1, csds_response.config_size());
const auto& client_config = csds_response.config(0);
// Validate the Node information
EXPECT_THAT(client_config.node(),
@ -615,6 +616,82 @@ TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterRequested) {
ClientResourceStatus::REQUESTED, ::testing::_))));
}
TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpMultiClient) {
Listener listener = default_listener_;
const char* kServer2Name = "server2.example.com";
listener.set_name(kServer2Name);
balancer_->ads_service()->SetLdsResource(listener);
SetListenerAndRouteConfiguration(balancer_.get(), listener,
default_route_config_);
CreateAndStartBackends(1);
const size_t kNumRpcs = 5;
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
// Send several RPCs to ensure the xDS setup works
CheckRpcSendOk(DEBUG_LOCATION, kNumRpcs);
// Connect to a second server
auto channel2 = CreateChannel(0, kServer2Name);
channel2->GetState(/*try_to_connect=*/true);
ASSERT_TRUE(channel2->WaitForConnected(grpc_timeout_seconds_to_deadline(1)));
// Fetches the client config
auto csds_response = FetchCsdsResponse();
ASSERT_EQ(2, csds_response.config_size());
std::vector<std::string> scopes;
for (const auto& client_config : csds_response.config()) {
// Validate the Node information
EXPECT_THAT(client_config.node(),
EqNode("xds_end2end_test", ::testing::HasSubstr("C-core"),
::testing::HasSubstr(grpc_version_string()),
::testing::ElementsAre(
"envoy.lb.does_not_support_overprovisioning")));
scopes.emplace_back(client_config.client_scope());
absl::string_view server = client_config.client_scope();
// Listener matcher depends on whether RDS is enabled.
::testing::Matcher<google::protobuf::Any> api_listener_matcher;
if (GetParam().enable_rds_testing()) {
api_listener_matcher = IsRdsEnabledHCM();
} else {
api_listener_matcher =
EqNoRdsHCM(kDefaultRouteConfigurationName, kDefaultClusterName);
}
// Construct list of all matchers.
std::vector<::testing::Matcher<
envoy::service::status::v3::ClientConfig_GenericXdsConfig>>
matchers = {
// Listener
EqGenericXdsConfig(
kLdsTypeUrl, absl::StripPrefix(server, "xds:"), "3",
UnpackListener(EqListener(absl::StripPrefix(server, "xds:"),
api_listener_matcher)),
ClientResourceStatus::ACKED, ::testing::_),
// Cluster
EqGenericXdsConfig(kCdsTypeUrl, kDefaultClusterName, "1",
UnpackCluster(EqCluster(kDefaultClusterName)),
ClientResourceStatus::ACKED, ::testing::_),
// ClusterLoadAssignment
EqGenericXdsConfig(
kEdsTypeUrl, kDefaultEdsServiceName, "1",
UnpackClusterLoadAssignment(EqClusterLoadAssignment(
kDefaultEdsServiceName, backends_[0]->port(),
kDefaultLocalityWeight)),
ClientResourceStatus::ACKED, ::testing::_),
};
// If RDS is enabled, add matcher for RDS resource.
if (GetParam().enable_rds_testing()) {
matchers.push_back(EqGenericXdsConfig(
kRdsTypeUrl, kDefaultRouteConfigurationName, "2",
UnpackRouteConfiguration(EqRouteConfiguration(
kDefaultRouteConfigurationName, kDefaultClusterName)),
ClientResourceStatus::ACKED, ::testing::_));
}
// Validate the dumped xDS configs
EXPECT_THAT(client_config.generic_xds_configs(),
::testing::UnorderedElementsAreArray(matchers));
}
EXPECT_THAT(scopes, ::testing::UnorderedElementsAre(
"xds:server.example.com", "xds:server2.example.com"));
}
class CsdsShortAdsTimeoutTest : public ClientStatusDiscoveryServiceTest {
protected:
void SetUp() override {

@ -523,7 +523,7 @@ void XdsEnd2endTest::InitClient(XdsBootstrapBuilder builder,
// because it's not expecting the client to connect. It also
// ensures that each test can independently set the global channel
// args for the xDS channel.
grpc_core::internal::UnsetGlobalXdsClientForTest();
grpc_core::internal::UnsetGlobalXdsClientsForTest();
}
// Create channel and stub.
ResetStub();
@ -558,7 +558,14 @@ std::shared_ptr<Channel> XdsEnd2endTest::CreateChannel(
GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS,
&xds_channel_args_, &kChannelArgsArgVtable);
}
std::string uri = absl::StrCat("xds://", xds_authority, "/", server_name);
std::vector<absl::string_view> parts = {"xds:"};
if (xds_authority != nullptr && xds_authority[0] != '\0') {
parts.emplace_back("//");
parts.emplace_back(xds_authority);
parts.emplace_back("/");
}
parts.emplace_back(server_name);
std::string uri = absl::StrJoin(parts, "");
std::shared_ptr<ChannelCredentials> channel_creds =
GetParam().use_xds_credentials()
? XdsCredentials(CreateTlsFallbackCredentials())

@ -113,7 +113,7 @@ TEST_P(WrrTest, MetricsHaveLocalityLabel) {
grpc_core::GlobalInstrumentsRegistryTestPeer::
FindDoubleHistogramHandleByName("grpc.lb.wrr.endpoint_weights")
.value();
const std::string target = absl::StrCat("xds:///", kServerName);
const std::string target = absl::StrCat("xds:", kServerName);
const absl::string_view kLabelValues[] = {/*target=*/target};
// Register stats plugin before initializing client.
auto stats_plugin = grpc_core::FakeStatsPluginBuilder()
@ -137,10 +137,7 @@ TEST_P(WrrTest, MetricsHaveLocalityLabel) {
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)},
{"locality1", CreateEndpointsForBackends(1, 2)}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
CheckRpcSendOk(DEBUG_LOCATION, 10);
// Both backends got some requests. The exact count doesn't matter.
EXPECT_GT(backends_[0]->backend_service()->request_count(), 0);
EXPECT_GT(backends_[1]->backend_service()->request_count(), 0);
WaitForAllBackends(DEBUG_LOCATION);
// Make sure we have a metric value for each of the two localities.
EXPECT_THAT(
stats_plugin->GetHistogramValue(kEndpointWeights, kLabelValues,

@ -52,34 +52,22 @@ static void StreamingPingPongArgs(benchmark::internal::Benchmark* b) {
}
}
BENCHMARK_TEMPLATE(BM_StreamingPingPong, InProcessCHTTP2, NoOpMutator,
NoOpMutator)
->Apply(StreamingPingPongArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPong, TCP, NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPong, InProcess, NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, InProcessCHTTP2, NoOpMutator,
NoOpMutator)
->Range(0, kMaxMessageSize);
BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, TCP, NoOpMutator, NoOpMutator)
->Range(0, kMaxMessageSize);
BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, InProcess, NoOpMutator,
NoOpMutator)
->Range(0, kMaxMessageSize);
BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinInProcessCHTTP2, NoOpMutator,
NoOpMutator)
->Apply(StreamingPingPongArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinTCP, NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinInProcess, NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinInProcessCHTTP2, NoOpMutator,
NoOpMutator)
->Range(0, kMaxMessageSize);
BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinTCP, NoOpMutator, NoOpMutator)
->Range(0, kMaxMessageSize);
BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinInProcess, NoOpMutator,
@ -106,12 +94,6 @@ static void StreamingPingPongWithCoalescingApiArgs(
}
}
BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, InProcessCHTTP2,
NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongWithCoalescingApiArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, MinInProcessCHTTP2,
NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongWithCoalescingApiArgs);
BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, InProcess,
NoOpMutator, NoOpMutator)
->Apply(StreamingPingPongWithCoalescingApiArgs);

@ -35,24 +35,18 @@ BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcess)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcessCHTTP2)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, TCP)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, UDS)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcess)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcessCHTTP2)
->Range(0, 128 * 1024 * 1024);
BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinTCP)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinUDS)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinInProcess)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinInProcessCHTTP2)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinTCP)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinUDS)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinInProcess)->Arg(0);
BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinInProcessCHTTP2)->Arg(0);
} // namespace testing
} // namespace grpc

@ -56,61 +56,6 @@ BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinSockPair, NoOpMutator, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator, NoOpMutator)
->Apply(SweepSizesArgs);
BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinInProcessCHTTP2, NoOpMutator,
NoOpMutator)
->Apply(SweepSizesArgs);
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomBinaryMetadata<31>, 1>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomBinaryMetadata<10>, 2>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomBinaryMetadata<31>, 2>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2,
Client_AddMetadata<RandomAsciiMetadata<100>, 1>, NoOpMutator)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
->Args({0, 0});
BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
->Args({0, 0});

@ -40,7 +40,6 @@
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/server.h"
#include "src/cpp/client/create_channel_internal.h"
#include "test/core/util/passthru_endpoint.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/microbenchmarks/helpers.h"
@ -254,45 +253,6 @@ class SockPair : public EndpointPairFixture {
fixture_configuration) {}
};
// Use InProcessCHTTP2 instead. This class (with stats as an explicit parameter)
// is here only to be able to initialize both the base class and stats_ with the
// same stats instance without accessing the stats_ fields before the object is
// properly initialized.
class InProcessCHTTP2WithExplicitStats : public EndpointPairFixture {
public:
InProcessCHTTP2WithExplicitStats(
Service* service, grpc_passthru_endpoint_stats* stats,
const FixtureConfiguration& fixture_configuration)
: EndpointPairFixture(service, MakeEndpoints(stats),
fixture_configuration),
stats_(stats) {}
~InProcessCHTTP2WithExplicitStats() override {
if (stats_ != nullptr) {
grpc_passthru_endpoint_stats_destroy(stats_);
}
}
private:
grpc_passthru_endpoint_stats* stats_;
static grpc_endpoint_pair MakeEndpoints(grpc_passthru_endpoint_stats* stats) {
grpc_endpoint_pair p;
grpc_passthru_endpoint_create(&p.client, &p.server, stats);
return p;
}
};
class InProcessCHTTP2 : public InProcessCHTTP2WithExplicitStats {
public:
explicit InProcessCHTTP2(Service* service,
const FixtureConfiguration& fixture_configuration =
FixtureConfiguration())
: InProcessCHTTP2WithExplicitStats(service,
grpc_passthru_endpoint_stats_create(),
fixture_configuration) {}
};
////////////////////////////////////////////////////////////////////////////////
// Minimal stack fixtures
@ -319,7 +279,6 @@ typedef MinStackize<TCP> MinTCP;
typedef MinStackize<UDS> MinUDS;
typedef MinStackize<InProcess> MinInProcess;
typedef MinStackize<SockPair> MinSockPair;
typedef MinStackize<InProcessCHTTP2> MinInProcessCHTTP2;
} // namespace testing
} // namespace grpc

Loading…
Cancel
Save