grpc 1.26.0 → 1.27.0.pre1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1654 -1519
  3. data/etc/roots.pem +44 -0
  4. data/include/grpc/grpc_security.h +37 -15
  5. data/include/grpc/grpc_security_constants.h +27 -0
  6. data/include/grpc/impl/codegen/grpc_types.h +14 -0
  7. data/include/grpc/impl/codegen/port_platform.h +1 -1
  8. data/src/core/ext/filters/client_channel/client_channel.cc +0 -20
  9. data/src/core/ext/filters/client_channel/http_proxy.cc +4 -4
  10. data/src/core/ext/filters/client_channel/lb_policy.cc +4 -3
  11. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +191 -201
  12. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc +89 -0
  13. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h +40 -0
  14. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc +3 -2
  15. data/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc +88 -121
  16. data/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h +28 -57
  17. data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +0 -7
  18. data/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc +8 -9
  19. data/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +53 -34
  20. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +18 -5
  21. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +24 -19
  22. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +2 -1
  23. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc +4 -2
  24. data/src/core/ext/filters/client_channel/server_address.cc +6 -9
  25. data/src/core/ext/filters/client_channel/server_address.h +3 -10
  26. data/src/core/ext/filters/client_channel/xds/xds_api.cc +394 -150
  27. data/src/core/ext/filters/client_channel/xds/xds_api.h +75 -35
  28. data/src/core/ext/filters/client_channel/xds/xds_bootstrap.cc +59 -22
  29. data/src/core/ext/filters/client_channel/xds/xds_bootstrap.h +13 -9
  30. data/src/core/ext/filters/client_channel/xds/xds_channel_secure.cc +8 -6
  31. data/src/core/ext/filters/client_channel/xds/xds_client.cc +456 -175
  32. data/src/core/ext/filters/client_channel/xds/xds_client.h +33 -21
  33. data/src/core/ext/filters/client_channel/xds/xds_client_stats.cc +5 -8
  34. data/src/core/ext/filters/client_channel/xds/xds_client_stats.h +18 -24
  35. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +2 -2
  36. data/src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c +13 -5
  37. data/src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.h +34 -0
  38. data/src/core/lib/channel/channelz.h +11 -1
  39. data/src/core/lib/gpr/time_precise.cc +1 -1
  40. data/src/core/lib/gprpp/optional.h +26 -0
  41. data/src/core/lib/gprpp/string_view.h +14 -10
  42. data/src/core/lib/iomgr/executor.cc +1 -1
  43. data/src/core/lib/iomgr/fork_posix.cc +4 -0
  44. data/src/core/lib/iomgr/poller/eventmanager_libuv.cc +87 -0
  45. data/src/core/lib/iomgr/poller/eventmanager_libuv.h +88 -0
  46. data/src/core/lib/iomgr/socket_utils_common_posix.cc +14 -0
  47. data/src/core/lib/iomgr/socket_utils_posix.h +12 -0
  48. data/src/core/lib/iomgr/tcp_custom.h +3 -0
  49. data/src/core/lib/iomgr/tcp_posix.cc +607 -56
  50. data/src/core/lib/iomgr/tcp_server_custom.cc +15 -2
  51. data/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +8 -0
  52. data/src/core/lib/json/json.h +11 -1
  53. data/src/core/lib/json/json_reader.cc +206 -28
  54. data/src/core/lib/json/json_writer.cc +111 -24
  55. data/src/core/lib/security/credentials/composite/composite_credentials.cc +7 -0
  56. data/src/core/lib/security/credentials/composite/composite_credentials.h +5 -1
  57. data/src/core/lib/security/credentials/credentials.h +10 -1
  58. data/src/core/lib/security/credentials/fake/fake_credentials.h +2 -1
  59. data/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +1 -1
  60. data/src/core/lib/security/credentials/plugin/plugin_credentials.cc +6 -4
  61. data/src/core/lib/security/credentials/plugin/plugin_credentials.h +2 -1
  62. data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +20 -0
  63. data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h +8 -0
  64. data/src/core/lib/security/credentials/tls/{spiffe_credentials.cc → tls_credentials.cc} +23 -24
  65. data/src/core/lib/security/credentials/tls/{spiffe_credentials.h → tls_credentials.h} +9 -9
  66. data/src/core/lib/security/security_connector/alts/alts_security_connector.cc +13 -0
  67. data/src/core/lib/security/security_connector/fake/fake_security_connector.cc +22 -2
  68. data/src/core/lib/security/security_connector/load_system_roots_fallback.cc +2 -2
  69. data/src/core/lib/security/security_connector/load_system_roots_linux.cc +2 -2
  70. data/src/core/lib/security/security_connector/local/local_security_connector.cc +30 -3
  71. data/src/core/lib/security/security_connector/ssl_utils.cc +45 -3
  72. data/src/core/lib/security/security_connector/ssl_utils.h +12 -0
  73. data/src/core/lib/security/security_connector/tls/{spiffe_security_connector.cc → tls_security_connector.cc} +82 -69
  74. data/src/core/lib/security/security_connector/tls/{spiffe_security_connector.h → tls_security_connector.h} +17 -18
  75. data/src/core/lib/security/transport/client_auth_filter.cc +33 -0
  76. data/src/core/lib/surface/completion_queue.cc +22 -1
  77. data/src/core/lib/surface/version.cc +1 -1
  78. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +11 -1
  79. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h +1 -1
  80. data/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc +3 -3
  81. data/src/core/tsi/fake_transport_security.cc +7 -3
  82. data/src/core/tsi/fake_transport_security.h +2 -0
  83. data/src/core/tsi/ssl_transport_security.cc +144 -8
  84. data/src/core/tsi/ssl_transport_security.h +15 -1
  85. data/src/core/tsi/transport_security.cc +13 -0
  86. data/src/core/tsi/transport_security_grpc.cc +2 -2
  87. data/src/core/tsi/transport_security_grpc.h +2 -2
  88. data/src/core/tsi/transport_security_interface.h +12 -0
  89. data/src/ruby/bin/math_pb.rb +5 -5
  90. data/src/ruby/ext/grpc/rb_call_credentials.c +4 -1
  91. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +2 -0
  92. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +4 -1
  93. data/src/ruby/lib/grpc/version.rb +1 -1
  94. data/src/ruby/pb/grpc/health/v1/health_pb.rb +3 -3
  95. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +1 -1
  96. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +23 -13
  97. data/third_party/abseil-cpp/absl/algorithm/algorithm.h +159 -0
  98. data/third_party/abseil-cpp/absl/base/attributes.h +609 -0
  99. data/third_party/abseil-cpp/absl/base/call_once.h +226 -0
  100. data/third_party/abseil-cpp/absl/base/casts.h +184 -0
  101. data/third_party/abseil-cpp/absl/base/config.h +622 -0
  102. data/third_party/abseil-cpp/absl/base/const_init.h +76 -0
  103. data/third_party/abseil-cpp/absl/base/dynamic_annotations.cc +129 -0
  104. data/third_party/abseil-cpp/absl/base/dynamic_annotations.h +389 -0
  105. data/third_party/abseil-cpp/absl/base/internal/atomic_hook.h +179 -0
  106. data/third_party/abseil-cpp/absl/base/internal/bits.h +218 -0
  107. data/third_party/abseil-cpp/absl/base/internal/cycleclock.cc +107 -0
  108. data/third_party/abseil-cpp/absl/base/internal/cycleclock.h +94 -0
  109. data/third_party/abseil-cpp/absl/base/internal/endian.h +266 -0
  110. data/third_party/abseil-cpp/absl/base/internal/hide_ptr.h +51 -0
  111. data/third_party/abseil-cpp/absl/base/internal/identity.h +37 -0
  112. data/third_party/abseil-cpp/absl/base/internal/inline_variable.h +107 -0
  113. data/third_party/abseil-cpp/absl/base/internal/invoke.h +187 -0
  114. data/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h +107 -0
  115. data/third_party/abseil-cpp/absl/base/internal/per_thread_tls.h +52 -0
  116. data/third_party/abseil-cpp/absl/base/internal/raw_logging.cc +237 -0
  117. data/third_party/abseil-cpp/absl/base/internal/raw_logging.h +179 -0
  118. data/third_party/abseil-cpp/absl/base/internal/scheduling_mode.h +58 -0
  119. data/third_party/abseil-cpp/absl/base/internal/spinlock.cc +233 -0
  120. data/third_party/abseil-cpp/absl/base/internal/spinlock.h +243 -0
  121. data/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc +35 -0
  122. data/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc +67 -0
  123. data/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc +46 -0
  124. data/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc +81 -0
  125. data/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h +93 -0
  126. data/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc +37 -0
  127. data/third_party/abseil-cpp/absl/base/internal/sysinfo.cc +414 -0
  128. data/third_party/abseil-cpp/absl/base/internal/sysinfo.h +66 -0
  129. data/third_party/abseil-cpp/absl/base/internal/thread_annotations.h +271 -0
  130. data/third_party/abseil-cpp/absl/base/internal/thread_identity.cc +140 -0
  131. data/third_party/abseil-cpp/absl/base/internal/thread_identity.h +250 -0
  132. data/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc +108 -0
  133. data/third_party/abseil-cpp/absl/base/internal/throw_delegate.h +75 -0
  134. data/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h +66 -0
  135. data/third_party/abseil-cpp/absl/base/internal/unaligned_access.h +158 -0
  136. data/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc +103 -0
  137. data/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h +124 -0
  138. data/third_party/abseil-cpp/absl/base/log_severity.cc +27 -0
  139. data/third_party/abseil-cpp/absl/base/log_severity.h +121 -0
  140. data/third_party/abseil-cpp/absl/base/macros.h +220 -0
  141. data/third_party/abseil-cpp/absl/base/optimization.h +181 -0
  142. data/third_party/abseil-cpp/absl/base/options.h +214 -0
  143. data/third_party/abseil-cpp/absl/base/policy_checks.h +111 -0
  144. data/third_party/abseil-cpp/absl/base/port.h +26 -0
  145. data/third_party/abseil-cpp/absl/base/thread_annotations.h +280 -0
  146. data/third_party/abseil-cpp/absl/container/inlined_vector.h +848 -0
  147. data/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h +265 -0
  148. data/third_party/abseil-cpp/absl/container/internal/inlined_vector.h +892 -0
  149. data/third_party/abseil-cpp/absl/memory/memory.h +695 -0
  150. data/third_party/abseil-cpp/absl/meta/type_traits.h +759 -0
  151. data/third_party/abseil-cpp/absl/numeric/int128.cc +404 -0
  152. data/third_party/abseil-cpp/absl/numeric/int128.h +1091 -0
  153. data/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc +302 -0
  154. data/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc +308 -0
  155. data/third_party/abseil-cpp/absl/strings/ascii.cc +200 -0
  156. data/third_party/abseil-cpp/absl/strings/ascii.h +241 -0
  157. data/third_party/abseil-cpp/absl/strings/charconv.cc +985 -0
  158. data/third_party/abseil-cpp/absl/strings/charconv.h +119 -0
  159. data/third_party/abseil-cpp/absl/strings/escaping.cc +949 -0
  160. data/third_party/abseil-cpp/absl/strings/escaping.h +164 -0
  161. data/third_party/abseil-cpp/absl/strings/internal/char_map.h +156 -0
  162. data/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc +359 -0
  163. data/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h +421 -0
  164. data/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc +504 -0
  165. data/third_party/abseil-cpp/absl/strings/internal/charconv_parse.h +99 -0
  166. data/third_party/abseil-cpp/absl/strings/internal/escaping.cc +180 -0
  167. data/third_party/abseil-cpp/absl/strings/internal/escaping.h +58 -0
  168. data/third_party/abseil-cpp/absl/strings/internal/memutil.cc +112 -0
  169. data/third_party/abseil-cpp/absl/strings/internal/memutil.h +148 -0
  170. data/third_party/abseil-cpp/absl/strings/internal/ostringstream.cc +36 -0
  171. data/third_party/abseil-cpp/absl/strings/internal/ostringstream.h +89 -0
  172. data/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized.h +73 -0
  173. data/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h +248 -0
  174. data/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h +314 -0
  175. data/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h +455 -0
  176. data/third_party/abseil-cpp/absl/strings/internal/utf8.cc +53 -0
  177. data/third_party/abseil-cpp/absl/strings/internal/utf8.h +50 -0
  178. data/third_party/abseil-cpp/absl/strings/match.cc +40 -0
  179. data/third_party/abseil-cpp/absl/strings/match.h +90 -0
  180. data/third_party/abseil-cpp/absl/strings/numbers.cc +916 -0
  181. data/third_party/abseil-cpp/absl/strings/numbers.h +263 -0
  182. data/third_party/abseil-cpp/absl/strings/str_cat.cc +246 -0
  183. data/third_party/abseil-cpp/absl/strings/str_cat.h +408 -0
  184. data/third_party/abseil-cpp/absl/strings/str_join.h +293 -0
  185. data/third_party/abseil-cpp/absl/strings/str_replace.cc +82 -0
  186. data/third_party/abseil-cpp/absl/strings/str_replace.h +219 -0
  187. data/third_party/abseil-cpp/absl/strings/str_split.cc +139 -0
  188. data/third_party/abseil-cpp/absl/strings/str_split.h +513 -0
  189. data/third_party/abseil-cpp/absl/strings/string_view.cc +235 -0
  190. data/third_party/abseil-cpp/absl/strings/string_view.h +615 -0
  191. data/third_party/abseil-cpp/absl/strings/strip.h +91 -0
  192. data/third_party/abseil-cpp/absl/strings/substitute.cc +171 -0
  193. data/third_party/abseil-cpp/absl/strings/substitute.h +693 -0
  194. data/third_party/abseil-cpp/absl/types/bad_optional_access.cc +48 -0
  195. data/third_party/abseil-cpp/absl/types/bad_optional_access.h +78 -0
  196. data/third_party/abseil-cpp/absl/types/internal/optional.h +396 -0
  197. data/third_party/abseil-cpp/absl/types/internal/span.h +128 -0
  198. data/third_party/abseil-cpp/absl/types/optional.h +776 -0
  199. data/third_party/abseil-cpp/absl/types/span.h +713 -0
  200. data/third_party/abseil-cpp/absl/utility/utility.h +350 -0
  201. data/third_party/upb/upb/decode.c +4 -0
  202. data/third_party/upb/upb/port.c +0 -1
  203. data/third_party/upb/upb/port_def.inc +1 -3
  204. data/third_party/upb/upb/table.c +2 -1
  205. metadata +147 -43
  206. data/src/core/lib/json/json_common.h +0 -34
  207. data/src/core/lib/json/json_reader.h +0 -146
  208. data/src/core/lib/json/json_string.cc +0 -367
  209. data/src/core/lib/json/json_writer.h +0 -84
@@ -23,14 +23,47 @@
23
23
 
24
24
  #include <stdint.h>
25
25
 
26
+ #include <set>
27
+
26
28
  #include <grpc/slice_buffer.h>
27
29
 
28
30
  #include "src/core/ext/filters/client_channel/server_address.h"
29
31
  #include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
30
32
  #include "src/core/ext/filters/client_channel/xds/xds_client_stats.h"
33
+ #include "src/core/lib/gprpp/optional.h"
31
34
 
32
35
  namespace grpc_core {
33
36
 
37
+ constexpr char kCdsTypeUrl[] = "type.googleapis.com/envoy.api.v2.Cluster";
38
+ constexpr char kEdsTypeUrl[] =
39
+ "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
40
+
41
+ // The version state for each specific ADS resource type.
42
+ struct VersionState {
43
+ // The version of the latest response that is accepted and used.
44
+ std::string version_info;
45
+ // The nonce of the latest response.
46
+ std::string nonce;
47
+ // The error message to be included in a NACK with the nonce. Consumed when a
48
+ // nonce is NACK'ed for the first time.
49
+ grpc_error* error = GRPC_ERROR_NONE;
50
+
51
+ ~VersionState() { GRPC_ERROR_UNREF(error); }
52
+ };
53
+
54
+ struct CdsUpdate {
55
+ // The name to use in the EDS request.
56
+ // If empty, the cluster name will be used.
57
+ std::string eds_service_name;
58
+ // The LRS server to use for load reporting.
59
+ // If not set, load reporting will be disabled.
60
+ // If set to the empty string, will use the same server we obtained the CDS
61
+ // data from.
62
+ Optional<std::string> lrs_load_reporting_server_name;
63
+ };
64
+
65
+ using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>;
66
+
34
67
  class XdsPriorityListUpdate {
35
68
  public:
36
69
  struct LocalityMap {
@@ -97,24 +130,22 @@ class XdsDropConfig : public RefCounted<XdsDropConfig> {
97
130
  public:
98
131
  struct DropCategory {
99
132
  bool operator==(const DropCategory& other) const {
100
- return strcmp(name.get(), other.name.get()) == 0 &&
101
- parts_per_million == other.parts_per_million;
133
+ return name == other.name && parts_per_million == other.parts_per_million;
102
134
  }
103
135
 
104
- grpc_core::UniquePtr<char> name;
136
+ std::string name;
105
137
  const uint32_t parts_per_million;
106
138
  };
107
139
 
108
140
  using DropCategoryList = InlinedVector<DropCategory, 2>;
109
141
 
110
- void AddCategory(grpc_core::UniquePtr<char> name,
111
- uint32_t parts_per_million) {
142
+ void AddCategory(std::string name, uint32_t parts_per_million) {
112
143
  drop_category_list_.emplace_back(
113
144
  DropCategory{std::move(name), parts_per_million});
114
145
  }
115
146
 
116
147
  // The only method invoked from the data plane combiner.
117
- bool ShouldDrop(const grpc_core::UniquePtr<char>** category_name) const;
148
+ bool ShouldDrop(const std::string** category_name) const;
118
149
 
119
150
  const DropCategoryList& drop_category_list() const {
120
151
  return drop_category_list_;
@@ -137,44 +168,53 @@ struct EdsUpdate {
137
168
  bool drop_all = false;
138
169
  };
139
170
 
140
- struct CdsUpdate {
141
- // The name to use in the EDS request.
142
- // If null, the cluster name will be used.
143
- grpc_core::UniquePtr<char> eds_service_name;
144
- // The LRS server to use for load reporting.
145
- // If null, load reporting will be disabled.
146
- // If set to the empty string, will use the same server we obtained
147
- // the CDS data from.
148
- grpc_core::UniquePtr<char> lrs_load_reporting_server_name;
149
- };
150
-
151
- // Creates an EDS request querying \a service_name.
152
- grpc_slice XdsEdsRequestCreateAndEncode(const char* server_name,
153
- const XdsBootstrap::Node* node,
154
- const char* build_version);
155
-
156
- // Parses the EDS response and returns the args to update locality map. If there
157
- // is any error, the output update is invalid.
158
- grpc_error* XdsEdsResponseDecodeAndParse(const grpc_slice& encoded_response,
159
- EdsUpdate* update);
171
+ using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>;
172
+
173
+ // Creates a request to nack an unsupported resource type.
174
+ // Takes ownership of \a error.
175
+ grpc_slice XdsUnsupportedTypeNackRequestCreateAndEncode(
176
+ const std::string& type_url, const std::string& nonce, grpc_error* error);
177
+
178
+ // Creates a CDS request querying \a cluster_names.
179
+ // Takes ownership of \a error.
180
+ grpc_slice XdsCdsRequestCreateAndEncode(
181
+ const std::set<StringView>& cluster_names, const XdsBootstrap::Node* node,
182
+ const char* build_version, const std::string& version,
183
+ const std::string& nonce, grpc_error* error);
184
+
185
+ // Creates an EDS request querying \a eds_service_names.
186
+ // Takes ownership of \a error.
187
+ grpc_slice XdsEdsRequestCreateAndEncode(
188
+ const std::set<StringView>& eds_service_names,
189
+ const XdsBootstrap::Node* node, const char* build_version,
190
+ const std::string& version, const std::string& nonce, grpc_error* error);
191
+
192
+ // Parses the ADS response and outputs the validated update for either CDS or
193
+ // EDS. If the response can't be parsed at the top level, \a type_url will point
194
+ // to an empty string; otherwise, it will point to the received data.
195
+ grpc_error* XdsAdsResponseDecodeAndParse(
196
+ const grpc_slice& encoded_response,
197
+ const std::set<StringView>& expected_eds_service_names,
198
+ CdsUpdateMap* cds_update_map, EdsUpdateMap* eds_update_map,
199
+ std::string* version, std::string* nonce, std::string* type_url);
160
200
 
161
201
  // Creates an LRS request querying \a server_name.
162
- grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name,
202
+ grpc_slice XdsLrsRequestCreateAndEncode(const std::string& server_name,
163
203
  const XdsBootstrap::Node* node,
164
204
  const char* build_version);
165
205
 
166
206
  // Creates an LRS request sending client-side load reports. If all the counters
167
- // in \a client_stats are zero, returns empty slice.
168
- grpc_slice XdsLrsRequestCreateAndEncode(const char* server_name,
169
- XdsClientStats* client_stats);
207
+ // are zero, returns empty slice.
208
+ grpc_slice XdsLrsRequestCreateAndEncode(
209
+ std::map<StringView /*cluster_name*/, std::set<XdsClientStats*>>
210
+ client_stats_map);
170
211
 
171
- // Parses the LRS response and returns \a cluster_name and \a
212
+ // Parses the LRS response and returns \a
172
213
  // load_reporting_interval for client-side load reporting. If there is any
173
214
  // error, the output config is invalid.
174
- grpc_error* XdsLrsResponseDecodeAndParse(
175
- const grpc_slice& encoded_response,
176
- grpc_core::UniquePtr<char>* cluster_name,
177
- grpc_millis* load_reporting_interval);
215
+ grpc_error* XdsLrsResponseDecodeAndParse(const grpc_slice& encoded_response,
216
+ std::set<std::string>* cluster_names,
217
+ grpc_millis* load_reporting_interval);
178
218
 
179
219
  } // namespace grpc_core
180
220
 
@@ -58,23 +58,23 @@ XdsBootstrap::XdsBootstrap(grpc_slice contents, grpc_error** error)
58
58
  return;
59
59
  }
60
60
  InlinedVector<grpc_error*, 1> error_list;
61
- bool seen_xds_server = false;
61
+ bool seen_xds_servers = false;
62
62
  bool seen_node = false;
63
63
  for (grpc_json* child = tree_->child; child != nullptr; child = child->next) {
64
64
  if (child->key == nullptr) {
65
65
  error_list.push_back(
66
66
  GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null"));
67
- } else if (strcmp(child->key, "xds_server") == 0) {
68
- if (child->type != GRPC_JSON_OBJECT) {
67
+ } else if (strcmp(child->key, "xds_servers") == 0) {
68
+ if (child->type != GRPC_JSON_ARRAY) {
69
69
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
70
- "\"xds_server\" field is not an object"));
70
+ "\"xds_servers\" field is not an array"));
71
71
  }
72
- if (seen_xds_server) {
72
+ if (seen_xds_servers) {
73
73
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
74
- "duplicate \"xds_server\" field"));
74
+ "duplicate \"xds_servers\" field"));
75
75
  }
76
- seen_xds_server = true;
77
- grpc_error* parse_error = ParseXdsServer(child);
76
+ seen_xds_servers = true;
77
+ grpc_error* parse_error = ParseXdsServerList(child);
78
78
  if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
79
79
  } else if (strcmp(child->key, "node") == 0) {
80
80
  if (child->type != GRPC_JSON_OBJECT) {
@@ -90,9 +90,9 @@ XdsBootstrap::XdsBootstrap(grpc_slice contents, grpc_error** error)
90
90
  if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
91
91
  }
92
92
  }
93
- if (!seen_xds_server) {
93
+ if (!seen_xds_servers) {
94
94
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
95
- "\"xds_server\" field not present"));
95
+ "\"xds_servers\" field not present"));
96
96
  }
97
97
  *error = GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing xds bootstrap file",
98
98
  &error_list);
@@ -103,9 +103,33 @@ XdsBootstrap::~XdsBootstrap() {
103
103
  grpc_slice_unref_internal(contents_);
104
104
  }
105
105
 
106
- grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json) {
106
+ grpc_error* XdsBootstrap::ParseXdsServerList(grpc_json* json) {
107
107
  InlinedVector<grpc_error*, 1> error_list;
108
- server_uri_ = nullptr;
108
+ size_t idx = 0;
109
+ for (grpc_json *child = json->child; child != nullptr;
110
+ child = child->next, ++idx) {
111
+ if (child->key != nullptr) {
112
+ char* msg;
113
+ gpr_asprintf(&msg, "array element %" PRIuPTR " key is not null", idx);
114
+ error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
115
+ }
116
+ if (child->type != GRPC_JSON_OBJECT) {
117
+ char* msg;
118
+ gpr_asprintf(&msg, "array element %" PRIuPTR " is not an object", idx);
119
+ error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
120
+ } else {
121
+ grpc_error* parse_error = ParseXdsServer(child, idx);
122
+ if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
123
+ }
124
+ }
125
+ return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"xds_servers\" array",
126
+ &error_list);
127
+ }
128
+
129
+ grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json, size_t idx) {
130
+ InlinedVector<grpc_error*, 1> error_list;
131
+ servers_.emplace_back();
132
+ XdsServer& server = servers_[servers_.size() - 1];
109
133
  bool seen_channel_creds = false;
110
134
  for (grpc_json* child = json->child; child != nullptr; child = child->next) {
111
135
  if (child->key == nullptr) {
@@ -116,11 +140,11 @@ grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json) {
116
140
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
117
141
  "\"server_uri\" field is not a string"));
118
142
  }
119
- if (server_uri_ != nullptr) {
143
+ if (server.server_uri != nullptr) {
120
144
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
121
145
  "duplicate \"server_uri\" field"));
122
146
  }
123
- server_uri_ = child->value;
147
+ server.server_uri = child->value;
124
148
  } else if (strcmp(child->key, "channel_creds") == 0) {
125
149
  if (child->type != GRPC_JSON_ARRAY) {
126
150
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -131,19 +155,29 @@ grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json) {
131
155
  "duplicate \"channel_creds\" field"));
132
156
  }
133
157
  seen_channel_creds = true;
134
- grpc_error* parse_error = ParseChannelCredsArray(child);
158
+ grpc_error* parse_error = ParseChannelCredsArray(child, &server);
135
159
  if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
136
160
  }
137
161
  }
138
- if (server_uri_ == nullptr) {
162
+ if (server.server_uri == nullptr) {
139
163
  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
140
164
  "\"server_uri\" field not present"));
141
165
  }
142
- return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"xds_server\" object",
143
- &error_list);
166
+ // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
167
+ // string is not static in this case.
168
+ if (error_list.empty()) return GRPC_ERROR_NONE;
169
+ char* msg;
170
+ gpr_asprintf(&msg, "errors parsing index %" PRIuPTR, idx);
171
+ grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
172
+ gpr_free(msg);
173
+ for (size_t i = 0; i < error_list.size(); ++i) {
174
+ error = grpc_error_add_child(error, error_list[i]);
175
+ }
176
+ return error;
144
177
  }
145
178
 
146
- grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json) {
179
+ grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json,
180
+ XdsServer* server) {
147
181
  InlinedVector<grpc_error*, 1> error_list;
148
182
  size_t idx = 0;
149
183
  for (grpc_json *child = json->child; child != nullptr;
@@ -158,7 +192,7 @@ grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json) {
158
192
  gpr_asprintf(&msg, "array element %" PRIuPTR " is not an object", idx);
159
193
  error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
160
194
  } else {
161
- grpc_error* parse_error = ParseChannelCreds(child, idx);
195
+ grpc_error* parse_error = ParseChannelCreds(child, idx, server);
162
196
  if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error);
163
197
  }
164
198
  }
@@ -166,7 +200,8 @@ grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json) {
166
200
  &error_list);
167
201
  }
168
202
 
169
- grpc_error* XdsBootstrap::ParseChannelCreds(grpc_json* json, size_t idx) {
203
+ grpc_error* XdsBootstrap::ParseChannelCreds(grpc_json* json, size_t idx,
204
+ XdsServer* server) {
170
205
  InlinedVector<grpc_error*, 1> error_list;
171
206
  ChannelCreds channel_creds;
172
207
  for (grpc_json* child = json->child; child != nullptr; child = child->next) {
@@ -195,7 +230,9 @@ grpc_error* XdsBootstrap::ParseChannelCreds(grpc_json* json, size_t idx) {
195
230
  channel_creds.config = child;
196
231
  }
197
232
  }
198
- if (channel_creds.type != nullptr) channel_creds_.push_back(channel_creds);
233
+ if (channel_creds.type != nullptr) {
234
+ server->channel_creds.push_back(channel_creds);
235
+ }
199
236
  // Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
200
237
  // string is not static in this case.
201
238
  if (error_list.empty()) return GRPC_ERROR_NONE;
@@ -58,6 +58,11 @@ class XdsBootstrap {
58
58
  grpc_json* config = nullptr;
59
59
  };
60
60
 
61
+ struct XdsServer {
62
+ const char* server_uri = nullptr;
63
+ InlinedVector<ChannelCreds, 1> channel_creds;
64
+ };
65
+
61
66
  // If *error is not GRPC_ERROR_NONE after returning, then there was an
62
67
  // error reading the file.
63
68
  static std::unique_ptr<XdsBootstrap> ReadFromFile(grpc_error** error);
@@ -66,16 +71,16 @@ class XdsBootstrap {
66
71
  XdsBootstrap(grpc_slice contents, grpc_error** error);
67
72
  ~XdsBootstrap();
68
73
 
69
- const char* server_uri() const { return server_uri_; }
70
- const InlinedVector<ChannelCreds, 1>& channel_creds() const {
71
- return channel_creds_;
72
- }
74
+ // TODO(roth): We currently support only one server. Fix this when we
75
+ // add support for fallback for the xds channel.
76
+ const XdsServer& server() const { return servers_[0]; }
73
77
  const Node* node() const { return node_.get(); }
74
78
 
75
79
  private:
76
- grpc_error* ParseXdsServer(grpc_json* json);
77
- grpc_error* ParseChannelCredsArray(grpc_json* json);
78
- grpc_error* ParseChannelCreds(grpc_json* json, size_t idx);
80
+ grpc_error* ParseXdsServerList(grpc_json* json);
81
+ grpc_error* ParseXdsServer(grpc_json* json, size_t idx);
82
+ grpc_error* ParseChannelCredsArray(grpc_json* json, XdsServer* server);
83
+ grpc_error* ParseChannelCreds(grpc_json* json, size_t idx, XdsServer* server);
79
84
  grpc_error* ParseNode(grpc_json* json);
80
85
  grpc_error* ParseLocality(grpc_json* json);
81
86
 
@@ -90,8 +95,7 @@ class XdsBootstrap {
90
95
  grpc_slice contents_;
91
96
  grpc_json* tree_ = nullptr;
92
97
 
93
- const char* server_uri_ = nullptr;
94
- InlinedVector<ChannelCreds, 1> channel_creds_;
98
+ InlinedVector<XdsServer, 1> servers_;
95
99
  std::unique_ptr<Node> node_;
96
100
  };
97
101
 
@@ -67,12 +67,14 @@ grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
67
67
  const grpc_channel_args& args) {
68
68
  grpc_channel_credentials* creds = nullptr;
69
69
  RefCountedPtr<grpc_channel_credentials> creds_to_unref;
70
- if (!bootstrap.channel_creds().empty()) {
71
- for (size_t i = 0; i < bootstrap.channel_creds().size(); ++i) {
72
- if (strcmp(bootstrap.channel_creds()[i].type, "google_default") == 0) {
70
+ if (!bootstrap.server().channel_creds.empty()) {
71
+ for (size_t i = 0; i < bootstrap.server().channel_creds.size(); ++i) {
72
+ if (strcmp(bootstrap.server().channel_creds[i].type, "google_default") ==
73
+ 0) {
73
74
  creds = grpc_google_default_credentials_create();
74
75
  break;
75
- } else if (strcmp(bootstrap.channel_creds()[i].type, "fake") == 0) {
76
+ } else if (strcmp(bootstrap.server().channel_creds[i].type, "fake") ==
77
+ 0) {
76
78
  creds = grpc_fake_transport_security_credentials_create();
77
79
  break;
78
80
  }
@@ -83,7 +85,7 @@ grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
83
85
  creds = grpc_channel_credentials_find_in_args(&args);
84
86
  if (creds == nullptr) {
85
87
  // Built with security but parent channel is insecure.
86
- return grpc_insecure_channel_create(bootstrap.server_uri(), &args,
88
+ return grpc_insecure_channel_create(bootstrap.server().server_uri, &args,
87
89
  nullptr);
88
90
  }
89
91
  }
@@ -91,7 +93,7 @@ grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
91
93
  grpc_channel_args* new_args =
92
94
  grpc_channel_args_copy_and_remove(&args, &arg_to_remove, 1);
93
95
  grpc_channel* channel = grpc_secure_channel_create(
94
- creds, bootstrap.server_uri(), new_args, nullptr);
96
+ creds, bootstrap.server().server_uri, new_args, nullptr);
95
97
  grpc_channel_args_destroy(new_args);
96
98
  return channel;
97
99
  }
@@ -125,10 +125,35 @@ class XdsClient::ChannelState::AdsCallState
125
125
  XdsClient* xds_client() const { return chand()->xds_client(); }
126
126
  bool seen_response() const { return seen_response_; }
127
127
 
128
+ // If \a type_url is an unsupported type, \a nonce_for_unsupported_type and
129
+ // \a error_for_unsupported_type will be used in the request; otherwise, the
130
+ // nonce and error stored in each ADS call state will be used. Takes ownership
131
+ // of \a error_for_unsupported_type.
132
+ void SendMessageLocked(const std::string& type_url,
133
+ const std::string& nonce_for_unsupported_type,
134
+ grpc_error* error_for_unsupported_type,
135
+ bool is_first_message);
136
+
128
137
  private:
138
+ struct BufferedRequest {
139
+ std::string nonce;
140
+ grpc_error* error;
141
+
142
+ // Takes ownership of \a error.
143
+ BufferedRequest(std::string nonce, grpc_error* error)
144
+ : nonce(std::move(nonce)), error(error) {}
145
+
146
+ ~BufferedRequest() { GRPC_ERROR_UNREF(error); }
147
+ };
148
+
149
+ void AcceptCdsUpdate(CdsUpdateMap cds_update_map, std::string new_version);
150
+ void AcceptEdsUpdate(EdsUpdateMap eds_update_map, std::string new_version);
151
+
152
+ static void OnRequestSent(void* arg, grpc_error* error);
153
+ static void OnRequestSentLocked(void* arg, grpc_error* error);
129
154
  static void OnResponseReceived(void* arg, grpc_error* error);
130
- static void OnStatusReceived(void* arg, grpc_error* error);
131
155
  static void OnResponseReceivedLocked(void* arg, grpc_error* error);
156
+ static void OnStatusReceived(void* arg, grpc_error* error);
132
157
  static void OnStatusReceivedLocked(void* arg, grpc_error* error);
133
158
 
134
159
  bool IsCurrentCallOnChannel() const;
@@ -145,6 +170,7 @@ class XdsClient::ChannelState::AdsCallState
145
170
 
146
171
  // send_message
147
172
  grpc_byte_buffer* send_message_payload_ = nullptr;
173
+ grpc_closure on_request_sent_;
148
174
 
149
175
  // recv_message
150
176
  grpc_byte_buffer* recv_message_payload_ = nullptr;
@@ -155,6 +181,14 @@ class XdsClient::ChannelState::AdsCallState
155
181
  grpc_status_code status_code_;
156
182
  grpc_slice status_details_;
157
183
  grpc_closure on_status_received_;
184
+
185
+ // Version state.
186
+ VersionState cds_version_;
187
+ VersionState eds_version_;
188
+
189
+ // Buffered requests.
190
+ std::map<std::string /*type_url*/, std::unique_ptr<BufferedRequest>>
191
+ buffered_request_map_;
158
192
  };
159
193
 
160
194
  // Contains an LRS call to the xds server.
@@ -168,6 +202,7 @@ class XdsClient::ChannelState::LrsCallState
168
202
  void Orphan() override;
169
203
 
170
204
  void MaybeStartReportingLocked();
205
+ bool ShouldSendLoadReports(const StringView& cluster_name) const;
171
206
 
172
207
  RetryableCall<LrsCallState>* parent() { return parent_.get(); }
173
208
  ChannelState* chand() const { return parent_->chand(); }
@@ -244,7 +279,7 @@ class XdsClient::ChannelState::LrsCallState
244
279
  grpc_closure on_status_received_;
245
280
 
246
281
  // Load reporting state.
247
- grpc_core::UniquePtr<char> cluster_name_;
282
+ std::set<std::string> cluster_names_; // Asked for by the LRS server.
248
283
  grpc_millis load_reporting_interval_ = 0;
249
284
  OrphanablePtr<Reporter> reporter_;
250
285
  };
@@ -376,14 +411,6 @@ bool XdsClient::ChannelState::HasActiveAdsCall() const {
376
411
  return ads_calld_->calld() != nullptr;
377
412
  }
378
413
 
379
- void XdsClient::ChannelState::MaybeStartAdsCall() {
380
- if (ads_calld_ != nullptr) return;
381
- ads_calld_.reset(
382
- new RetryableCall<AdsCallState>(Ref(DEBUG_LOCATION, "ChannelState+ads")));
383
- }
384
-
385
- void XdsClient::ChannelState::StopAdsCall() { ads_calld_.reset(); }
386
-
387
414
  void XdsClient::ChannelState::MaybeStartLrsCall() {
388
415
  if (lrs_calld_ != nullptr) return;
389
416
  lrs_calld_.reset(
@@ -409,6 +436,33 @@ void XdsClient::ChannelState::CancelConnectivityWatchLocked() {
409
436
  grpc_client_channel_stop_connectivity_watch(client_channel_elem, watcher_);
410
437
  }
411
438
 
439
+ void XdsClient::ChannelState::OnResourceNamesChanged(
440
+ const std::string& type_url) {
441
+ if (ads_calld_ == nullptr) {
442
+ // Start the ADS call if this is the first request.
443
+ ads_calld_.reset(new RetryableCall<AdsCallState>(
444
+ Ref(DEBUG_LOCATION, "ChannelState+ads")));
445
+ // Note: AdsCallState's ctor will automatically send necessary messages, so
446
+ // we can return here.
447
+ return;
448
+ }
449
+ // If the ADS call is in backoff state, we don't need to do anything now
450
+ // because when the call is restarted it will resend all necessary requests.
451
+ if (ads_calld() == nullptr) return;
452
+ // Send the message if the ADS call is active.
453
+ ads_calld()->SendMessageLocked(type_url, "", nullptr, false);
454
+ }
455
+
456
+ void XdsClient::ChannelState::OnWatcherRemoved() {
457
+ // Keep the ADS call if there are watcher(s).
458
+ for (const auto& p : xds_client()->cluster_map_) {
459
+ const ClusterState& cluster_state = p.second;
460
+ if (!cluster_state.watchers.empty()) return;
461
+ }
462
+ if (!xds_client()->endpoint_map_.empty()) return;
463
+ ads_calld_.reset();
464
+ }
465
+
412
466
  //
413
467
  // XdsClient::ChannelState::RetryableCall<>
414
468
  //
@@ -522,8 +576,7 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
522
576
  // activity in xds_client()->interested_parties_, which is comprised of
523
577
  // the polling entities from client_channel.
524
578
  GPR_ASSERT(xds_client() != nullptr);
525
- GPR_ASSERT(xds_client()->server_name_ != nullptr);
526
- GPR_ASSERT(*xds_client()->server_name_.get() != '\0');
579
+ GPR_ASSERT(!xds_client()->server_name_.empty());
527
580
  // Create a call with the specified method name.
528
581
  call_ = grpc_channel_create_pollset_set_call(
529
582
  chand()->channel_, nullptr, GRPC_PROPAGATE_DEFAULTS,
@@ -531,14 +584,7 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
531
584
  GRPC_MDSTR_SLASH_ENVOY_DOT_SERVICE_DOT_DISCOVERY_DOT_V2_DOT_AGGREGATEDDISCOVERYSERVICE_SLASH_STREAMAGGREGATEDRESOURCES,
532
585
  nullptr, GRPC_MILLIS_INF_FUTURE, nullptr);
533
586
  GPR_ASSERT(call_ != nullptr);
534
- // Init the request payload.
535
- grpc_slice request_payload_slice = XdsEdsRequestCreateAndEncode(
536
- xds_client()->server_name_.get(), xds_client()->bootstrap_->node(),
537
- xds_client()->build_version_.get());
538
- send_message_payload_ =
539
- grpc_raw_byte_buffer_create(&request_payload_slice, 1);
540
- grpc_slice_unref_internal(request_payload_slice);
541
- // Init other data associated with the call.
587
+ // Init data associated with the call.
542
588
  grpc_metadata_array_init(&initial_metadata_recv_);
543
589
  grpc_metadata_array_init(&trailing_metadata_recv_);
544
590
  // Start the call.
@@ -559,16 +605,20 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
559
605
  op->flags = 0;
560
606
  op->reserved = nullptr;
561
607
  op++;
562
- // Op: send request message.
563
- GPR_ASSERT(send_message_payload_ != nullptr);
564
- op->op = GRPC_OP_SEND_MESSAGE;
565
- op->data.send_message.send_message = send_message_payload_;
566
- op->flags = 0;
567
- op->reserved = nullptr;
568
- op++;
569
608
  call_error = grpc_call_start_batch_and_execute(call_, ops, (size_t)(op - ops),
570
609
  nullptr);
571
610
  GPR_ASSERT(GRPC_CALL_OK == call_error);
611
+ // Op: send request message.
612
+ GRPC_CLOSURE_INIT(&on_request_sent_, OnRequestSent, this,
613
+ grpc_schedule_on_exec_ctx);
614
+ bool initial_message = true;
615
+ if (!xds_client()->cluster_map_.empty()) {
616
+ SendMessageLocked(kCdsTypeUrl, "", nullptr, initial_message);
617
+ initial_message = false;
618
+ }
619
+ if (!xds_client()->endpoint_map_.empty()) {
620
+ SendMessageLocked(kEdsTypeUrl, "", nullptr, initial_message);
621
+ }
572
622
  // Op: recv initial metadata.
573
623
  op = ops;
574
624
  op->op = GRPC_OP_RECV_INITIAL_METADATA;
@@ -629,86 +679,126 @@ void XdsClient::ChannelState::AdsCallState::Orphan() {
629
679
  // corresponding unref happens in on_status_received_ instead of here.
630
680
  }
631
681
 
632
- void XdsClient::ChannelState::AdsCallState::OnResponseReceived(
633
- void* arg, grpc_error* error) {
634
- AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
635
- ads_calld->xds_client()->combiner_->Run(
636
- GRPC_CLOSURE_INIT(&ads_calld->on_response_received_,
637
- OnResponseReceivedLocked, ads_calld, nullptr),
638
- GRPC_ERROR_REF(error));
639
- }
640
-
641
- void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
642
- void* arg, grpc_error* /*error*/) {
643
- AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
644
- XdsClient* xds_client = ads_calld->xds_client();
645
- // Empty payload means the call was cancelled.
646
- if (!ads_calld->IsCurrentCallOnChannel() ||
647
- ads_calld->recv_message_payload_ == nullptr) {
648
- ads_calld->Unref(DEBUG_LOCATION, "ADS+OnResponseReceivedLocked");
682
+ void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
683
+ const std::string& type_url, const std::string& nonce_for_unsupported_type,
684
+ grpc_error* error_for_unsupported_type, bool is_first_message) {
685
+ // Buffer message sending if an existing message is in flight.
686
+ if (send_message_payload_ != nullptr) {
687
+ buffered_request_map_[type_url].reset(new BufferedRequest(
688
+ nonce_for_unsupported_type, error_for_unsupported_type));
649
689
  return;
650
690
  }
651
- // Read the response.
652
- grpc_byte_buffer_reader bbr;
653
- grpc_byte_buffer_reader_init(&bbr, ads_calld->recv_message_payload_);
654
- grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
655
- grpc_byte_buffer_reader_destroy(&bbr);
656
- grpc_byte_buffer_destroy(ads_calld->recv_message_payload_);
657
- ads_calld->recv_message_payload_ = nullptr;
658
- // TODO(juanlishen): When we convert this to use the xds protocol, the
659
- // balancer will send us a fallback timeout such that we should go into
660
- // fallback mode if we have lost contact with the balancer after a certain
661
- // period of time. We will need to save the timeout value here, and then
662
- // when the balancer call ends, we will need to start a timer for the
663
- // specified period of time, and if the timer fires, we go into fallback
664
- // mode. We will also need to cancel the timer when we receive a serverlist
665
- // from the balancer.
666
- // This anonymous lambda is a hack to avoid the usage of goto.
667
- [&]() {
668
- // Parse the response.
669
- EdsUpdate update;
670
- grpc_error* parse_error =
671
- XdsEdsResponseDecodeAndParse(response_slice, &update);
672
- if (parse_error != GRPC_ERROR_NONE) {
673
- gpr_log(GPR_ERROR,
674
- "[xds_client %p] ADS response parsing failed. error=%s",
675
- xds_client, grpc_error_string(parse_error));
676
- GRPC_ERROR_UNREF(parse_error);
677
- return;
691
+ grpc_slice request_payload_slice;
692
+ const XdsBootstrap::Node* node =
693
+ is_first_message ? xds_client()->bootstrap_->node() : nullptr;
694
+ const char* build_version =
695
+ is_first_message ? xds_client()->build_version_.get() : nullptr;
696
+ if (type_url == kCdsTypeUrl) {
697
+ request_payload_slice = XdsCdsRequestCreateAndEncode(
698
+ xds_client()->WatchedClusterNames(), node, build_version,
699
+ cds_version_.version_info, cds_version_.nonce, cds_version_.error);
700
+ cds_version_.error = GRPC_ERROR_NONE;
701
+ GRPC_ERROR_UNREF(error_for_unsupported_type);
702
+ } else if (type_url == kEdsTypeUrl) {
703
+ request_payload_slice = XdsEdsRequestCreateAndEncode(
704
+ xds_client()->EdsServiceNames(), node, build_version,
705
+ eds_version_.version_info, eds_version_.nonce, eds_version_.error);
706
+ eds_version_.error = GRPC_ERROR_NONE;
707
+ GRPC_ERROR_UNREF(error_for_unsupported_type);
708
+ } else {
709
+ request_payload_slice = XdsUnsupportedTypeNackRequestCreateAndEncode(
710
+ type_url, nonce_for_unsupported_type, error_for_unsupported_type);
711
+ }
712
+ // Create message payload.
713
+ send_message_payload_ =
714
+ grpc_raw_byte_buffer_create(&request_payload_slice, 1);
715
+ grpc_slice_unref_internal(request_payload_slice);
716
+ // Send the message.
717
+ grpc_op op;
718
+ memset(&op, 0, sizeof(op));
719
+ op.op = GRPC_OP_SEND_MESSAGE;
720
+ op.data.send_message.send_message = send_message_payload_;
721
+ Ref(DEBUG_LOCATION, "ADS+OnRequestSentLocked").release();
722
+ GRPC_CLOSURE_INIT(&on_request_sent_, OnRequestSent, this,
723
+ grpc_schedule_on_exec_ctx);
724
+ grpc_call_error call_error =
725
+ grpc_call_start_batch_and_execute(call_, &op, 1, &on_request_sent_);
726
+ if (GPR_UNLIKELY(call_error != GRPC_CALL_OK)) {
727
+ gpr_log(GPR_ERROR,
728
+ "[xds_client %p] calld=%p call_error=%d sending ADS message",
729
+ xds_client(), this, call_error);
730
+ GPR_ASSERT(GRPC_CALL_OK == call_error);
731
+ }
732
+ }
733
+
734
+ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
735
+ CdsUpdateMap cds_update_map, std::string new_version) {
736
+ for (auto& p : cds_update_map) {
737
+ const char* cluster_name = p.first.c_str();
738
+ CdsUpdate& cds_update = p.second;
739
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
740
+ gpr_log(GPR_INFO,
741
+ "[xds_client %p] CDS update (cluster=%s) received: "
742
+ "eds_service_name=%s, "
743
+ "lrs_load_reporting_server_name=%s",
744
+ xds_client(), cluster_name, cds_update.eds_service_name.c_str(),
745
+ cds_update.lrs_load_reporting_server_name.has_value()
746
+ ? cds_update.lrs_load_reporting_server_name.value().c_str()
747
+ : "(N/A)");
678
748
  }
679
- if (update.priority_list_update.empty() && !update.drop_all) {
680
- char* response_slice_str =
681
- grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX);
682
- gpr_log(GPR_ERROR,
683
- "[xds_client %p] ADS response '%s' doesn't contain any valid "
684
- "locality but doesn't require to drop all calls. Ignoring.",
685
- xds_client, response_slice_str);
686
- gpr_free(response_slice_str);
687
- return;
749
+ ClusterState& cluster_state = xds_client()->cluster_map_[cluster_name];
750
+ // Ignore identical update.
751
+ if (cluster_state.update.has_value() &&
752
+ cds_update.eds_service_name ==
753
+ cluster_state.update.value().eds_service_name &&
754
+ cds_update.lrs_load_reporting_server_name.value() ==
755
+ cluster_state.update.value()
756
+ .lrs_load_reporting_server_name.value()) {
757
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
758
+ gpr_log(GPR_INFO,
759
+ "[xds_client %p] CDS update identical to current, ignoring.",
760
+ xds_client());
761
+ }
762
+ continue;
763
+ }
764
+ // Update the cluster state.
765
+ cluster_state.update.set(std::move(cds_update));
766
+ // Notify all watchers.
767
+ for (const auto& p : cluster_state.watchers) {
768
+ p.first->OnClusterChanged(cluster_state.update.value());
688
769
  }
689
- ads_calld->seen_response_ = true;
770
+ }
771
+ cds_version_.version_info = std::move(new_version);
772
+ }
773
+
774
+ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
775
+ EdsUpdateMap eds_update_map, std::string new_version) {
776
+ for (auto& p : eds_update_map) {
777
+ const char* eds_service_name = p.first.c_str();
778
+ EdsUpdate& eds_update = p.second;
690
779
  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
691
780
  gpr_log(GPR_INFO,
692
- "[xds_client %p] ADS response with %" PRIuPTR
781
+ "[xds_client %p] EDS response with %" PRIuPTR
693
782
  " priorities and %" PRIuPTR
694
783
  " drop categories received (drop_all=%d)",
695
- xds_client, update.priority_list_update.size(),
696
- update.drop_config->drop_category_list().size(), update.drop_all);
697
- for (size_t priority = 0; priority < update.priority_list_update.size();
698
- ++priority) {
699
- const auto* locality_map_update =
700
- update.priority_list_update.Find(static_cast<uint32_t>(priority));
784
+ xds_client(), eds_update.priority_list_update.size(),
785
+ eds_update.drop_config->drop_category_list().size(),
786
+ eds_update.drop_all);
787
+ for (size_t priority = 0;
788
+ priority < eds_update.priority_list_update.size(); ++priority) {
789
+ const auto* locality_map_update = eds_update.priority_list_update.Find(
790
+ static_cast<uint32_t>(priority));
701
791
  gpr_log(GPR_INFO,
702
792
  "[xds_client %p] Priority %" PRIuPTR " contains %" PRIuPTR
703
793
  " localities",
704
- xds_client, priority, locality_map_update->size());
794
+ xds_client(), priority, locality_map_update->size());
705
795
  size_t locality_count = 0;
706
796
  for (const auto& p : locality_map_update->localities) {
707
797
  const auto& locality = p.second;
708
798
  gpr_log(GPR_INFO,
709
799
  "[xds_client %p] Priority %" PRIuPTR ", locality %" PRIuPTR
710
800
  " %s contains %" PRIuPTR " server addresses",
711
- xds_client, priority, locality_count,
801
+ xds_client(), priority, locality_count,
712
802
  locality.name->AsHumanReadableString(),
713
803
  locality.serverlist.size());
714
804
  for (size_t i = 0; i < locality.serverlist.size(); ++i) {
@@ -718,59 +808,184 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
718
808
  gpr_log(GPR_INFO,
719
809
  "[xds_client %p] Priority %" PRIuPTR ", locality %" PRIuPTR
720
810
  " %s, server address %" PRIuPTR ": %s",
721
- xds_client, priority, locality_count,
811
+ xds_client(), priority, locality_count,
722
812
  locality.name->AsHumanReadableString(), i, ipport);
723
813
  gpr_free(ipport);
724
814
  }
725
815
  ++locality_count;
726
816
  }
727
817
  }
728
- for (size_t i = 0; i < update.drop_config->drop_category_list().size();
729
- ++i) {
818
+ for (size_t i = 0;
819
+ i < eds_update.drop_config->drop_category_list().size(); ++i) {
730
820
  const XdsDropConfig::DropCategory& drop_category =
731
- update.drop_config->drop_category_list()[i];
821
+ eds_update.drop_config->drop_category_list()[i];
732
822
  gpr_log(GPR_INFO,
733
823
  "[xds_client %p] Drop category %s has drop rate %d per million",
734
- xds_client, drop_category.name.get(),
824
+ xds_client(), drop_category.name.c_str(),
735
825
  drop_category.parts_per_million);
736
826
  }
737
827
  }
738
- // Start load reporting if needed.
739
- auto& lrs_call = ads_calld->chand()->lrs_calld_;
740
- if (lrs_call != nullptr) {
741
- LrsCallState* lrs_calld = lrs_call->calld();
742
- if (lrs_calld != nullptr) lrs_calld->MaybeStartReportingLocked();
743
- }
828
+ EndpointState& endpoint_state =
829
+ xds_client()->endpoint_map_[eds_service_name];
744
830
  // Ignore identical update.
745
- const EdsUpdate& prev_update = xds_client->cluster_state_.eds_update;
831
+ const EdsUpdate& prev_update = endpoint_state.update;
746
832
  const bool priority_list_changed =
747
- prev_update.priority_list_update != update.priority_list_update;
833
+ prev_update.priority_list_update != eds_update.priority_list_update;
748
834
  const bool drop_config_changed =
749
835
  prev_update.drop_config == nullptr ||
750
- *prev_update.drop_config != *update.drop_config;
836
+ *prev_update.drop_config != *eds_update.drop_config;
751
837
  if (!priority_list_changed && !drop_config_changed) {
752
838
  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
753
839
  gpr_log(GPR_INFO,
754
840
  "[xds_client %p] EDS update identical to current, ignoring.",
755
- xds_client);
841
+ xds_client());
756
842
  }
757
- return;
843
+ continue;
758
844
  }
759
845
  // Update the cluster state.
760
- ClusterState& cluster_state = xds_client->cluster_state_;
761
- cluster_state.eds_update = std::move(update);
846
+ endpoint_state.update = std::move(eds_update);
762
847
  // Notify all watchers.
763
- for (const auto& p : cluster_state.endpoint_watchers) {
764
- p.first->OnEndpointChanged(cluster_state.eds_update);
848
+ for (const auto& p : endpoint_state.watchers) {
849
+ p.first->OnEndpointChanged(endpoint_state.update);
765
850
  }
766
- }();
851
+ }
852
+ eds_version_.version_info = std::move(new_version);
853
+ }
854
+
855
+ void XdsClient::ChannelState::AdsCallState::OnRequestSent(void* arg,
856
+ grpc_error* error) {
857
+ AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
858
+ ads_calld->xds_client()->combiner_->Run(
859
+ GRPC_CLOSURE_INIT(&ads_calld->on_request_sent_, OnRequestSentLocked,
860
+ ads_calld, nullptr),
861
+ GRPC_ERROR_REF(error));
862
+ }
863
+
864
+ void XdsClient::ChannelState::AdsCallState::OnRequestSentLocked(
865
+ void* arg, grpc_error* error) {
866
+ AdsCallState* self = static_cast<AdsCallState*>(arg);
867
+ if (self->IsCurrentCallOnChannel() && error == GRPC_ERROR_NONE) {
868
+ // Clean up the sent message.
869
+ grpc_byte_buffer_destroy(self->send_message_payload_);
870
+ self->send_message_payload_ = nullptr;
871
+ // Continue to send another pending message if any.
872
+ // TODO(roth): The current code to handle buffered messages has the
873
+ // advantage of sending only the most recent list of resource names for each
874
+ // resource type (no matter how many times that resource type has been
875
+ // requested to send while the current message sending is still pending).
876
+ // But its disadvantage is that we send the requests in fixed order of
877
+ // resource types. We need to fix this if we are seeing some resource
878
+ // type(s) starved due to frequent requests of other resource type(s).
879
+ for (auto& p : self->buffered_request_map_) {
880
+ const std::string& type_url = p.first;
881
+ std::unique_ptr<BufferedRequest>& buffered_request = p.second;
882
+ if (buffered_request != nullptr) {
883
+ self->SendMessageLocked(type_url, buffered_request->nonce,
884
+ buffered_request->error, false);
885
+ buffered_request->error = GRPC_ERROR_NONE;
886
+ buffered_request.reset();
887
+ break;
888
+ }
889
+ }
890
+ }
891
+ self->Unref(DEBUG_LOCATION, "ADS+OnRequestSentLocked");
892
+ }
893
+
894
+ void XdsClient::ChannelState::AdsCallState::OnResponseReceived(
895
+ void* arg, grpc_error* error) {
896
+ AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
897
+ ads_calld->xds_client()->combiner_->Run(
898
+ GRPC_CLOSURE_INIT(&ads_calld->on_response_received_,
899
+ OnResponseReceivedLocked, ads_calld, nullptr),
900
+ GRPC_ERROR_REF(error));
901
+ }
902
+
903
+ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
904
+ void* arg, grpc_error* /*error*/) {
905
+ AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
906
+ XdsClient* xds_client = ads_calld->xds_client();
907
+ // Empty payload means the call was cancelled.
908
+ if (!ads_calld->IsCurrentCallOnChannel() ||
909
+ ads_calld->recv_message_payload_ == nullptr) {
910
+ ads_calld->Unref(DEBUG_LOCATION, "ADS+OnResponseReceivedLocked");
911
+ return;
912
+ }
913
+ // Read the response.
914
+ grpc_byte_buffer_reader bbr;
915
+ grpc_byte_buffer_reader_init(&bbr, ads_calld->recv_message_payload_);
916
+ grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
917
+ grpc_byte_buffer_reader_destroy(&bbr);
918
+ grpc_byte_buffer_destroy(ads_calld->recv_message_payload_);
919
+ ads_calld->recv_message_payload_ = nullptr;
920
+ // TODO(juanlishen): When we convert this to use the xds protocol, the
921
+ // balancer will send us a fallback timeout such that we should go into
922
+ // fallback mode if we have lost contact with the balancer after a certain
923
+ // period of time. We will need to save the timeout value here, and then
924
+ // when the balancer call ends, we will need to start a timer for the
925
+ // specified period of time, and if the timer fires, we go into fallback
926
+ // mode. We will also need to cancel the timer when we receive a serverlist
927
+ // from the balancer.
928
+ // Parse the response.
929
+ CdsUpdateMap cds_update_map;
930
+ EdsUpdateMap eds_update_map;
931
+ std::string version;
932
+ std::string nonce;
933
+ std::string type_url;
934
+ // Note that XdsAdsResponseDecodeAndParse() also validate the response.
935
+ grpc_error* parse_error = XdsAdsResponseDecodeAndParse(
936
+ response_slice, xds_client->EdsServiceNames(), &cds_update_map,
937
+ &eds_update_map, &version, &nonce, &type_url);
767
938
  grpc_slice_unref_internal(response_slice);
939
+ if (type_url.empty()) {
940
+ // Ignore unparsable response.
941
+ gpr_log(GPR_ERROR, "[xds_client %p] No type_url found. error=%s",
942
+ xds_client, grpc_error_string(parse_error));
943
+ GRPC_ERROR_UNREF(parse_error);
944
+ } else {
945
+ // Update nonce and error.
946
+ if (type_url == kCdsTypeUrl) {
947
+ ads_calld->cds_version_.nonce = nonce;
948
+ GRPC_ERROR_UNREF(ads_calld->cds_version_.error);
949
+ ads_calld->cds_version_.error = GRPC_ERROR_REF(parse_error);
950
+ } else if (type_url == kEdsTypeUrl) {
951
+ ads_calld->eds_version_.nonce = nonce;
952
+ GRPC_ERROR_UNREF(ads_calld->eds_version_.error);
953
+ ads_calld->eds_version_.error = GRPC_ERROR_REF(parse_error);
954
+ }
955
+ // NACK or ACK the response.
956
+ if (parse_error != GRPC_ERROR_NONE) {
957
+ // NACK unacceptable update.
958
+ gpr_log(
959
+ GPR_ERROR,
960
+ "[xds_client %p] ADS response can't be accepted, NACKing. error=%s",
961
+ xds_client, grpc_error_string(parse_error));
962
+ ads_calld->SendMessageLocked(type_url, nonce, parse_error, false);
963
+ } else {
964
+ ads_calld->seen_response_ = true;
965
+ // Accept the (CDS or EDS) response.
966
+ if (type_url == kCdsTypeUrl) {
967
+ ads_calld->AcceptCdsUpdate(std::move(cds_update_map),
968
+ std::move(version));
969
+ } else if (type_url == kEdsTypeUrl) {
970
+ ads_calld->AcceptEdsUpdate(std::move(eds_update_map),
971
+ std::move(version));
972
+ }
973
+ // ACK the update.
974
+ ads_calld->SendMessageLocked(type_url, "", nullptr, false);
975
+ // Start load reporting if needed.
976
+ auto& lrs_call = ads_calld->chand()->lrs_calld_;
977
+ if (lrs_call != nullptr) {
978
+ LrsCallState* lrs_calld = lrs_call->calld();
979
+ if (lrs_calld != nullptr) lrs_calld->MaybeStartReportingLocked();
980
+ }
981
+ }
982
+ }
768
983
  if (xds_client->shutting_down_) {
769
984
  ads_calld->Unref(DEBUG_LOCATION,
770
985
  "ADS+OnResponseReceivedLocked+xds_shutdown");
771
986
  return;
772
987
  }
773
- // Keep listening for serverlist updates.
988
+ // Keep listening for updates.
774
989
  grpc_op op;
775
990
  memset(&op, 0, sizeof(op));
776
991
  op.op = GRPC_OP_RECV_MESSAGE;
@@ -869,15 +1084,8 @@ void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimerLocked(
869
1084
 
870
1085
  void XdsClient::ChannelState::LrsCallState::Reporter::SendReportLocked() {
871
1086
  // Create a request that contains the load report.
872
- // TODO(roth): Currently, it is not possible to have multiple client
873
- // stats objects for a given cluster. However, in the future, we may
874
- // run into cases where this happens (e.g., due to graceful LB policy
875
- // switching). If/when this becomes a problem, replace this assertion
876
- // with code to merge data from multiple client stats objects.
877
- GPR_ASSERT(xds_client()->cluster_state_.client_stats.size() == 1);
878
- auto* client_stats = *xds_client()->cluster_state_.client_stats.begin();
879
1087
  grpc_slice request_payload_slice =
880
- XdsLrsRequestCreateAndEncode(parent_->cluster_name_.get(), client_stats);
1088
+ XdsLrsRequestCreateAndEncode(xds_client()->ClientStatsMap());
881
1089
  // Skip client load report if the counters were all zero in the last
882
1090
  // report and they are still zero in this one.
883
1091
  const bool old_val = last_report_counters_were_zero_;
@@ -945,8 +1153,7 @@ XdsClient::ChannelState::LrsCallState::LrsCallState(
945
1153
  // activity in xds_client()->interested_parties_, which is comprised of
946
1154
  // the polling entities from client_channel.
947
1155
  GPR_ASSERT(xds_client() != nullptr);
948
- GPR_ASSERT(xds_client()->server_name_ != nullptr);
949
- GPR_ASSERT(*xds_client()->server_name_.get() != '\0');
1156
+ GPR_ASSERT(!xds_client()->server_name_.empty());
950
1157
  call_ = grpc_channel_create_pollset_set_call(
951
1158
  chand()->channel_, nullptr, GRPC_PROPAGATE_DEFAULTS,
952
1159
  xds_client()->interested_parties_,
@@ -955,7 +1162,7 @@ XdsClient::ChannelState::LrsCallState::LrsCallState(
955
1162
  GPR_ASSERT(call_ != nullptr);
956
1163
  // Init the request payload.
957
1164
  grpc_slice request_payload_slice = XdsLrsRequestCreateAndEncode(
958
- xds_client()->server_name_.get(), xds_client()->bootstrap_->node(),
1165
+ xds_client()->server_name_, xds_client()->bootstrap_->node(),
959
1166
  xds_client()->build_version_.get());
960
1167
  send_message_payload_ =
961
1168
  grpc_raw_byte_buffer_create(&request_payload_slice, 1);
@@ -1069,13 +1276,22 @@ void XdsClient::ChannelState::LrsCallState::MaybeStartReportingLocked() {
1069
1276
  AdsCallState* ads_calld = chand()->ads_calld_->calld();
1070
1277
  if (ads_calld == nullptr || !ads_calld->seen_response()) return;
1071
1278
  // Start reporting.
1072
- for (auto* client_stats : chand()->xds_client_->cluster_state_.client_stats) {
1073
- client_stats->MaybeInitLastReportTime();
1279
+ for (auto& p : chand()->xds_client_->endpoint_map_) {
1280
+ for (auto* client_stats : p.second.client_stats) {
1281
+ client_stats->MaybeInitLastReportTime();
1282
+ }
1074
1283
  }
1075
1284
  reporter_ = MakeOrphanable<Reporter>(
1076
1285
  Ref(DEBUG_LOCATION, "LRS+load_report+start"), load_reporting_interval_);
1077
1286
  }
1078
1287
 
1288
+ bool XdsClient::ChannelState::LrsCallState::ShouldSendLoadReports(
1289
+ const StringView& cluster_name) const {
1290
+ // Only send load reports for the clusters that are asked for by the LRS
1291
+ // server.
1292
+ return cluster_names_.find(std::string(cluster_name)) != cluster_names_.end();
1293
+ }
1294
+
1079
1295
  void XdsClient::ChannelState::LrsCallState::OnInitialRequestSent(
1080
1296
  void* arg, grpc_error* error) {
1081
1297
  LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
@@ -1124,10 +1340,10 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked(
1124
1340
  // This anonymous lambda is a hack to avoid the usage of goto.
1125
1341
  [&]() {
1126
1342
  // Parse the response.
1127
- grpc_core::UniquePtr<char> new_cluster_name;
1343
+ std::set<std::string> new_cluster_names;
1128
1344
  grpc_millis new_load_reporting_interval;
1129
1345
  grpc_error* parse_error = XdsLrsResponseDecodeAndParse(
1130
- response_slice, &new_cluster_name, &new_load_reporting_interval);
1346
+ response_slice, &new_cluster_names, &new_load_reporting_interval);
1131
1347
  if (parse_error != GRPC_ERROR_NONE) {
1132
1348
  gpr_log(GPR_ERROR,
1133
1349
  "[xds_client %p] LRS response parsing failed. error=%s",
@@ -1138,9 +1354,15 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked(
1138
1354
  lrs_calld->seen_response_ = true;
1139
1355
  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
1140
1356
  gpr_log(GPR_INFO,
1141
- "[xds_client %p] LRS response received, cluster_name=%s, "
1142
- "load_report_interval=%" PRId64 "ms",
1143
- xds_client, new_cluster_name.get(), new_load_reporting_interval);
1357
+ "[xds_client %p] LRS response received, %" PRIuPTR
1358
+ " cluster names, load_report_interval=%" PRId64 "ms",
1359
+ xds_client, new_cluster_names.size(),
1360
+ new_load_reporting_interval);
1361
+ size_t i = 0;
1362
+ for (const auto& name : new_cluster_names) {
1363
+ gpr_log(GPR_INFO, "[xds_client %p] cluster_name %" PRIuPTR ": %s",
1364
+ xds_client, i++, name.c_str());
1365
+ }
1144
1366
  }
1145
1367
  if (new_load_reporting_interval <
1146
1368
  GRPC_XDS_MIN_CLIENT_LOAD_REPORTING_INTERVAL_MS) {
@@ -1154,8 +1376,8 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked(
1154
1376
  }
1155
1377
  }
1156
1378
  // Ignore identical update.
1157
- if (lrs_calld->load_reporting_interval_ == new_load_reporting_interval &&
1158
- strcmp(lrs_calld->cluster_name_.get(), new_cluster_name.get()) == 0) {
1379
+ if (lrs_calld->cluster_names_ == new_cluster_names &&
1380
+ lrs_calld->load_reporting_interval_ == new_load_reporting_interval) {
1159
1381
  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
1160
1382
  gpr_log(GPR_INFO,
1161
1383
  "[xds_client %p] Incoming LRS response identical to current, "
@@ -1167,7 +1389,7 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked(
1167
1389
  // Stop current load reporting (if any) to adopt the new config.
1168
1390
  lrs_calld->reporter_.reset();
1169
1391
  // Record the new config.
1170
- lrs_calld->cluster_name_ = std::move(new_cluster_name);
1392
+ lrs_calld->cluster_names_ = std::move(new_cluster_names);
1171
1393
  lrs_calld->load_reporting_interval_ = new_load_reporting_interval;
1172
1394
  // Try starting sending load report.
1173
1395
  lrs_calld->MaybeStartReportingLocked();
@@ -1253,11 +1475,12 @@ XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
1253
1475
  StringView server_name,
1254
1476
  std::unique_ptr<ServiceConfigWatcherInterface> watcher,
1255
1477
  const grpc_channel_args& channel_args, grpc_error** error)
1256
- : build_version_(GenerateBuildVersionString()),
1478
+ : InternallyRefCounted<XdsClient>(&grpc_xds_client_trace),
1479
+ build_version_(GenerateBuildVersionString()),
1257
1480
  combiner_(GRPC_COMBINER_REF(combiner, "xds_client")),
1258
1481
  interested_parties_(interested_parties),
1259
1482
  bootstrap_(XdsBootstrap::ReadFromFile(error)),
1260
- server_name_(StringViewToCString(server_name)),
1483
+ server_name_(server_name),
1261
1484
  service_config_watcher_(std::move(watcher)) {
1262
1485
  if (*error != GRPC_ERROR_NONE) {
1263
1486
  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@@ -1268,7 +1491,7 @@ XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
1268
1491
  }
1269
1492
  if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
1270
1493
  gpr_log(GPR_INFO, "[xds_client %p: creating channel to %s", this,
1271
- bootstrap_->server_uri());
1494
+ bootstrap_->server().server_uri);
1272
1495
  }
1273
1496
  chand_ = MakeOrphanable<ChannelState>(
1274
1497
  Ref(DEBUG_LOCATION, "XdsClient+ChannelState"), channel_args);
@@ -1286,77 +1509,95 @@ XdsClient::~XdsClient() { GRPC_COMBINER_UNREF(combiner_, "xds_client"); }
1286
1509
  void XdsClient::Orphan() {
1287
1510
  shutting_down_ = true;
1288
1511
  chand_.reset();
1512
+ cluster_map_.clear();
1513
+ endpoint_map_.clear();
1289
1514
  Unref(DEBUG_LOCATION, "XdsClient::Orphan()");
1290
1515
  }
1291
1516
 
1292
1517
  void XdsClient::WatchClusterData(
1293
- StringView cluster, std::unique_ptr<ClusterWatcherInterface> watcher) {
1518
+ StringView cluster_name, std::unique_ptr<ClusterWatcherInterface> watcher) {
1519
+ const bool new_name = cluster_map_.find(cluster_name) == cluster_map_.end();
1520
+ ClusterState& cluster_state = cluster_map_[cluster_name];
1294
1521
  ClusterWatcherInterface* w = watcher.get();
1295
- cluster_state_.cluster_watchers[w] = std::move(watcher);
1296
- // TODO(juanlishen): Start CDS call if not already started and return
1297
- // real data via watcher.
1298
- CdsUpdate update;
1299
- update.eds_service_name = StringViewToCString(cluster);
1300
- update.lrs_load_reporting_server_name.reset(gpr_strdup(""));
1301
- w->OnClusterChanged(std::move(update));
1522
+ cluster_state.watchers[w] = std::move(watcher);
1523
+ // If we've already received an CDS update, notify the new watcher
1524
+ // immediately.
1525
+ if (cluster_state.update.has_value()) {
1526
+ w->OnClusterChanged(cluster_state.update.value());
1527
+ }
1528
+ if (new_name) chand_->OnResourceNamesChanged(kCdsTypeUrl);
1302
1529
  }
1303
1530
 
1304
- void XdsClient::CancelClusterDataWatch(StringView cluster,
1531
+ void XdsClient::CancelClusterDataWatch(StringView cluster_name,
1305
1532
  ClusterWatcherInterface* watcher) {
1306
- auto it = cluster_state_.cluster_watchers.find(watcher);
1307
- if (it != cluster_state_.cluster_watchers.end()) {
1308
- cluster_state_.cluster_watchers.erase(it);
1309
- }
1310
- if (chand_ != nullptr && cluster_state_.cluster_watchers.empty()) {
1311
- // TODO(juanlishen): Stop CDS call.
1533
+ if (shutting_down_) return;
1534
+ ClusterState& cluster_state = cluster_map_[cluster_name];
1535
+ auto it = cluster_state.watchers.find(watcher);
1536
+ if (it != cluster_state.watchers.end()) {
1537
+ cluster_state.watchers.erase(it);
1538
+ if (cluster_state.watchers.empty()) {
1539
+ cluster_map_.erase(cluster_name);
1540
+ chand_->OnResourceNamesChanged(kCdsTypeUrl);
1541
+ }
1312
1542
  }
1543
+ chand_->OnWatcherRemoved();
1313
1544
  }
1314
1545
 
1315
1546
  void XdsClient::WatchEndpointData(
1316
- StringView /*cluster*/, std::unique_ptr<EndpointWatcherInterface> watcher) {
1547
+ StringView eds_service_name,
1548
+ std::unique_ptr<EndpointWatcherInterface> watcher) {
1549
+ const bool new_name =
1550
+ endpoint_map_.find(eds_service_name) == endpoint_map_.end();
1551
+ EndpointState& endpoint_state = endpoint_map_[eds_service_name];
1317
1552
  EndpointWatcherInterface* w = watcher.get();
1318
- cluster_state_.endpoint_watchers[w] = std::move(watcher);
1553
+ endpoint_state.watchers[w] = std::move(watcher);
1319
1554
  // If we've already received an EDS update, notify the new watcher
1320
1555
  // immediately.
1321
- if (!cluster_state_.eds_update.priority_list_update.empty()) {
1322
- w->OnEndpointChanged(cluster_state_.eds_update);
1556
+ if (!endpoint_state.update.priority_list_update.empty()) {
1557
+ w->OnEndpointChanged(endpoint_state.update);
1323
1558
  }
1324
- chand_->MaybeStartAdsCall();
1559
+ if (new_name) chand_->OnResourceNamesChanged(kEdsTypeUrl);
1325
1560
  }
1326
1561
 
1327
- void XdsClient::CancelEndpointDataWatch(StringView /*cluster*/,
1562
+ void XdsClient::CancelEndpointDataWatch(StringView eds_service_name,
1328
1563
  EndpointWatcherInterface* watcher) {
1329
- auto it = cluster_state_.endpoint_watchers.find(watcher);
1330
- if (it != cluster_state_.endpoint_watchers.end()) {
1331
- cluster_state_.endpoint_watchers.erase(it);
1332
- }
1333
- if (chand_ != nullptr && cluster_state_.endpoint_watchers.empty()) {
1334
- chand_->StopAdsCall();
1564
+ if (shutting_down_) return;
1565
+ EndpointState& endpoint_state = endpoint_map_[eds_service_name];
1566
+ auto it = endpoint_state.watchers.find(watcher);
1567
+ if (it != endpoint_state.watchers.end()) {
1568
+ endpoint_state.watchers.erase(it);
1569
+ if (endpoint_state.watchers.empty()) {
1570
+ endpoint_map_.erase(eds_service_name);
1571
+ chand_->OnResourceNamesChanged(kEdsTypeUrl);
1572
+ }
1335
1573
  }
1574
+ chand_->OnWatcherRemoved();
1336
1575
  }
1337
1576
 
1338
1577
  void XdsClient::AddClientStats(StringView /*lrs_server*/,
1339
- StringView /*cluster*/,
1578
+ StringView cluster_name,
1340
1579
  XdsClientStats* client_stats) {
1580
+ EndpointState& endpoint_state = endpoint_map_[cluster_name];
1341
1581
  // TODO(roth): When we add support for direct federation, use the
1342
1582
  // server name specified in lrs_server.
1343
- cluster_state_.client_stats.insert(client_stats);
1583
+ endpoint_state.client_stats.insert(client_stats);
1344
1584
  chand_->MaybeStartLrsCall();
1345
1585
  }
1346
1586
 
1347
1587
  void XdsClient::RemoveClientStats(StringView /*lrs_server*/,
1348
- StringView /*cluster*/,
1588
+ StringView cluster_name,
1349
1589
  XdsClientStats* client_stats) {
1590
+ EndpointState& endpoint_state = endpoint_map_[cluster_name];
1350
1591
  // TODO(roth): When we add support for direct federation, use the
1351
1592
  // server name specified in lrs_server.
1352
1593
  // TODO(roth): In principle, we should try to send a final load report
1353
1594
  // containing whatever final stats have been accumulated since the
1354
1595
  // last load report.
1355
- auto it = cluster_state_.client_stats.find(client_stats);
1356
- if (it != cluster_state_.client_stats.end()) {
1357
- cluster_state_.client_stats.erase(it);
1596
+ auto it = endpoint_state.client_stats.find(client_stats);
1597
+ if (it != endpoint_state.client_stats.end()) {
1598
+ endpoint_state.client_stats.erase(it);
1358
1599
  }
1359
- if (chand_ != nullptr && cluster_state_.client_stats.empty()) {
1600
+ if (chand_ != nullptr && endpoint_state.client_stats.empty()) {
1360
1601
  chand_->StopLrsCall();
1361
1602
  }
1362
1603
  }
@@ -1367,15 +1608,55 @@ void XdsClient::ResetBackoff() {
1367
1608
  }
1368
1609
  }
1369
1610
 
1611
+ std::set<StringView> XdsClient::WatchedClusterNames() const {
1612
+ std::set<StringView> cluster_names;
1613
+ for (const auto& p : cluster_map_) {
1614
+ const StringView& cluster_name = p.first;
1615
+ const ClusterState& cluster_state = p.second;
1616
+ // Don't request for the clusters that are cached before watched.
1617
+ if (cluster_state.watchers.empty()) continue;
1618
+ cluster_names.emplace(cluster_name);
1619
+ }
1620
+ return cluster_names;
1621
+ }
1622
+
1623
+ std::set<StringView> XdsClient::EdsServiceNames() const {
1624
+ std::set<StringView> eds_service_names;
1625
+ for (const auto& p : endpoint_map_) {
1626
+ const StringView& eds_service_name = p.first;
1627
+ eds_service_names.emplace(eds_service_name);
1628
+ }
1629
+ return eds_service_names;
1630
+ }
1631
+
1632
+ std::map<StringView, std::set<XdsClientStats*>> XdsClient::ClientStatsMap()
1633
+ const {
1634
+ std::map<StringView, std::set<XdsClientStats*>> client_stats_map;
1635
+ for (const auto& p : endpoint_map_) {
1636
+ const StringView& cluster_name = p.first;
1637
+ const auto& client_stats = p.second.client_stats;
1638
+ if (chand_->lrs_calld()->ShouldSendLoadReports(cluster_name)) {
1639
+ client_stats_map.emplace(cluster_name, client_stats);
1640
+ }
1641
+ }
1642
+ return client_stats_map;
1643
+ }
1644
+
1370
1645
  void XdsClient::NotifyOnError(grpc_error* error) {
1371
1646
  if (service_config_watcher_ != nullptr) {
1372
1647
  service_config_watcher_->OnError(GRPC_ERROR_REF(error));
1373
1648
  }
1374
- for (const auto& p : cluster_state_.cluster_watchers) {
1375
- p.first->OnError(GRPC_ERROR_REF(error));
1649
+ for (const auto& p : cluster_map_) {
1650
+ const ClusterState& cluster_state = p.second;
1651
+ for (const auto& p : cluster_state.watchers) {
1652
+ p.first->OnError(GRPC_ERROR_REF(error));
1653
+ }
1376
1654
  }
1377
- for (const auto& p : cluster_state_.endpoint_watchers) {
1378
- p.first->OnError(GRPC_ERROR_REF(error));
1655
+ for (const auto& p : endpoint_map_) {
1656
+ const EndpointState& endpoint_state = p.second;
1657
+ for (const auto& p : endpoint_state.watchers) {
1658
+ p.first->OnError(GRPC_ERROR_REF(error));
1659
+ }
1379
1660
  }
1380
1661
  GRPC_ERROR_UNREF(error);
1381
1662
  }
@@ -1393,7 +1674,7 @@ void XdsClient::NotifyOnServiceConfig(void* arg, grpc_error* error) {
1393
1674
  " } }\n"
1394
1675
  " ]\n"
1395
1676
  "}",
1396
- self->server_name_.get());
1677
+ self->server_name_.c_str());
1397
1678
  RefCountedPtr<ServiceConfig> service_config =
1398
1679
  ServiceConfig::Create(json, &error);
1399
1680
  gpr_free(json);