grpc 1.28.0.pre2 → 1.28.0

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.

@@ -24,6 +24,8 @@
24
24
 
25
25
  namespace grpc_core {
26
26
 
27
+ TraceFlag grpc_xds_resolver_trace(false, "xds_resolver");
28
+
27
29
  namespace {
28
30
 
29
31
  //
@@ -38,14 +40,28 @@ class XdsResolver : public Resolver {
38
40
  interested_parties_(args.pollset_set) {
39
41
  char* path = args.uri->path;
40
42
  if (path[0] == '/') ++path;
41
- server_name_.reset(gpr_strdup(path));
43
+ server_name_ = path;
44
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
45
+ gpr_log(GPR_INFO, "[xds_resolver %p] created for server name %s", this,
46
+ server_name_.c_str());
47
+ }
42
48
  }
43
49
 
44
- ~XdsResolver() override { grpc_channel_args_destroy(args_); }
50
+ ~XdsResolver() override {
51
+ grpc_channel_args_destroy(args_);
52
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
53
+ gpr_log(GPR_INFO, "[xds_resolver %p] destroyed", this);
54
+ }
55
+ }
45
56
 
46
57
  void StartLocked() override;
47
58
 
48
- void ShutdownLocked() override { xds_client_.reset(); }
59
+ void ShutdownLocked() override {
60
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
61
+ gpr_log(GPR_INFO, "[xds_resolver %p] shutting down", this);
62
+ }
63
+ xds_client_.reset();
64
+ }
49
65
 
50
66
  private:
51
67
  class ServiceConfigWatcher : public XdsClient::ServiceConfigWatcherInterface {
@@ -60,7 +76,7 @@ class XdsResolver : public Resolver {
60
76
  RefCountedPtr<XdsResolver> resolver_;
61
77
  };
62
78
 
63
- grpc_core::UniquePtr<char> server_name_;
79
+ std::string server_name_;
64
80
  const grpc_channel_args* args_;
65
81
  grpc_pollset_set* interested_parties_;
66
82
  OrphanablePtr<XdsClient> xds_client_;
@@ -69,6 +85,10 @@ class XdsResolver : public Resolver {
69
85
  void XdsResolver::ServiceConfigWatcher::OnServiceConfigChanged(
70
86
  RefCountedPtr<ServiceConfig> service_config) {
71
87
  if (resolver_->xds_client_ == nullptr) return;
88
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) {
89
+ gpr_log(GPR_INFO, "[xds_resolver %p] received updated service config: %s",
90
+ resolver_.get(), service_config->json_string().c_str());
91
+ }
72
92
  grpc_arg xds_client_arg = resolver_->xds_client_->MakeChannelArg();
73
93
  Result result;
74
94
  result.args =
@@ -79,6 +99,8 @@ void XdsResolver::ServiceConfigWatcher::OnServiceConfigChanged(
79
99
 
80
100
  void XdsResolver::ServiceConfigWatcher::OnError(grpc_error* error) {
81
101
  if (resolver_->xds_client_ == nullptr) return;
102
+ gpr_log(GPR_ERROR, "[xds_resolver %p] received error: %s", resolver_.get(),
103
+ grpc_error_string(error));
82
104
  grpc_arg xds_client_arg = resolver_->xds_client_->MakeChannelArg();
83
105
  Result result;
84
106
  result.args =
@@ -90,7 +112,7 @@ void XdsResolver::ServiceConfigWatcher::OnError(grpc_error* error) {
90
112
  void XdsResolver::StartLocked() {
91
113
  grpc_error* error = GRPC_ERROR_NONE;
92
114
  xds_client_ = MakeOrphanable<XdsClient>(
93
- combiner(), interested_parties_, StringView(server_name_.get()),
115
+ combiner(), interested_parties_, server_name_,
94
116
  absl::make_unique<ServiceConfigWatcher>(Ref()), *args_, &error);
95
117
  if (error != GRPC_ERROR_NONE) {
96
118
  gpr_log(GPR_ERROR,
@@ -33,6 +33,7 @@
33
33
 
34
34
  #include "src/core/ext/filters/client_channel/backup_poller.h"
35
35
  #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
36
+ #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
36
37
  #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
37
38
  #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
38
39
  #include "src/core/ext/filters/client_channel/resolver_registry.h"
@@ -109,67 +110,31 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
109
110
  RefCountedPtr<SubchannelInterface> CreateSubchannel(
110
111
  const grpc_channel_args& args) override {
111
112
  if (parent_->resolver_ == nullptr) return nullptr; // Shutting down.
112
- if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
113
113
  return parent_->channel_control_helper()->CreateSubchannel(args);
114
114
  }
115
115
 
116
116
  void UpdateState(grpc_connectivity_state state,
117
117
  std::unique_ptr<SubchannelPicker> picker) override {
118
118
  if (parent_->resolver_ == nullptr) return; // Shutting down.
119
- // If this request is from the pending child policy, ignore it until
120
- // it reports READY, at which point we swap it into place.
121
- if (CalledByPendingChild()) {
122
- if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) {
123
- gpr_log(GPR_INFO,
124
- "resolving_lb=%p helper=%p: pending child policy %p reports "
125
- "state=%s",
126
- parent_.get(), this, child_, ConnectivityStateName(state));
127
- }
128
- if (state != GRPC_CHANNEL_READY) return;
129
- grpc_pollset_set_del_pollset_set(
130
- parent_->lb_policy_->interested_parties(),
131
- parent_->interested_parties());
132
- parent_->lb_policy_ = std::move(parent_->pending_lb_policy_);
133
- } else if (!CalledByCurrentChild()) {
134
- // This request is from an outdated child, so ignore it.
135
- return;
136
- }
137
119
  parent_->channel_control_helper()->UpdateState(state, std::move(picker));
138
120
  }
139
121
 
140
122
  void RequestReresolution() override {
141
- // If there is a pending child policy, ignore re-resolution requests
142
- // from the current child policy (or any outdated child).
143
- if (parent_->pending_lb_policy_ != nullptr && !CalledByPendingChild()) {
144
- return;
145
- }
123
+ if (parent_->resolver_ == nullptr) return; // Shutting down.
146
124
  if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) {
147
125
  gpr_log(GPR_INFO, "resolving_lb=%p: started name re-resolving",
148
126
  parent_.get());
149
127
  }
150
- if (parent_->resolver_ != nullptr) {
151
- parent_->resolver_->RequestReresolutionLocked();
152
- }
128
+ parent_->resolver_->RequestReresolutionLocked();
153
129
  }
154
130
 
155
- void AddTraceEvent(TraceSeverity /*severity*/,
156
- StringView /*message*/) override {}
157
-
158
- void set_child(LoadBalancingPolicy* child) { child_ = child; }
159
-
160
- private:
161
- bool CalledByPendingChild() const {
162
- GPR_ASSERT(child_ != nullptr);
163
- return child_ == parent_->pending_lb_policy_.get();
131
+ void AddTraceEvent(TraceSeverity severity, StringView message) override {
132
+ if (parent_->resolver_ == nullptr) return; // Shutting down.
133
+ parent_->channel_control_helper()->AddTraceEvent(severity, message);
164
134
  }
165
135
 
166
- bool CalledByCurrentChild() const {
167
- GPR_ASSERT(child_ != nullptr);
168
- return child_ == parent_->lb_policy_.get();
169
- };
170
-
136
+ private:
171
137
  RefCountedPtr<ResolvingLoadBalancingPolicy> parent_;
172
- LoadBalancingPolicy* child_ = nullptr;
173
138
  };
174
139
 
175
140
  //
@@ -217,23 +182,11 @@ void ResolvingLoadBalancingPolicy::ShutdownLocked() {
217
182
  interested_parties());
218
183
  lb_policy_.reset();
219
184
  }
220
- if (pending_lb_policy_ != nullptr) {
221
- if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
222
- gpr_log(GPR_INFO, "resolving_lb=%p: shutting down pending lb_policy=%p",
223
- this, pending_lb_policy_.get());
224
- }
225
- grpc_pollset_set_del_pollset_set(pending_lb_policy_->interested_parties(),
226
- interested_parties());
227
- pending_lb_policy_.reset();
228
- }
229
185
  }
230
186
  }
231
187
 
232
188
  void ResolvingLoadBalancingPolicy::ExitIdleLocked() {
233
- if (lb_policy_ != nullptr) {
234
- lb_policy_->ExitIdleLocked();
235
- if (pending_lb_policy_ != nullptr) pending_lb_policy_->ExitIdleLocked();
236
- }
189
+ if (lb_policy_ != nullptr) lb_policy_->ExitIdleLocked();
237
190
  }
238
191
 
239
192
  void ResolvingLoadBalancingPolicy::ResetBackoffLocked() {
@@ -242,7 +195,6 @@ void ResolvingLoadBalancingPolicy::ResetBackoffLocked() {
242
195
  resolver_->RequestReresolutionLocked();
243
196
  }
244
197
  if (lb_policy_ != nullptr) lb_policy_->ResetBackoffLocked();
245
- if (pending_lb_policy_ != nullptr) pending_lb_policy_->ResetBackoffLocked();
246
198
  }
247
199
 
248
200
  void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
@@ -269,132 +221,42 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
269
221
 
270
222
  void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
271
223
  RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
272
- Resolver::Result result, TraceStringVector* trace_strings) {
273
- // If the child policy name changes, we need to create a new child
274
- // policy. When this happens, we leave child_policy_ as-is and store
275
- // the new child policy in pending_child_policy_. Once the new child
276
- // policy transitions into state READY, we swap it into child_policy_,
277
- // replacing the original child policy. So pending_child_policy_ is
278
- // non-null only between when we apply an update that changes the child
279
- // policy name and when the new child reports state READY.
280
- //
281
- // Updates can arrive at any point during this transition. We always
282
- // apply updates relative to the most recently created child policy,
283
- // even if the most recent one is still in pending_child_policy_. This
284
- // is true both when applying the updates to an existing child policy
285
- // and when determining whether we need to create a new policy.
286
- //
287
- // As a result of this, there are several cases to consider here:
288
- //
289
- // 1. We have no existing child policy (i.e., we have started up but
290
- // have not yet received a serverlist from the balancer or gone
291
- // into fallback mode; in this case, both child_policy_ and
292
- // pending_child_policy_ are null). In this case, we create a
293
- // new child policy and store it in child_policy_.
294
- //
295
- // 2. We have an existing child policy and have no pending child policy
296
- // from a previous update (i.e., either there has not been a
297
- // previous update that changed the policy name, or we have already
298
- // finished swapping in the new policy; in this case, child_policy_
299
- // is non-null but pending_child_policy_ is null). In this case:
300
- // a. If child_policy_->name() equals child_policy_name, then we
301
- // update the existing child policy.
302
- // b. If child_policy_->name() does not equal child_policy_name,
303
- // we create a new policy. The policy will be stored in
304
- // pending_child_policy_ and will later be swapped into
305
- // child_policy_ by the helper when the new child transitions
306
- // into state READY.
307
- //
308
- // 3. We have an existing child policy and have a pending child policy
309
- // from a previous update (i.e., a previous update set
310
- // pending_child_policy_ as per case 2b above and that policy has
311
- // not yet transitioned into state READY and been swapped into
312
- // child_policy_; in this case, both child_policy_ and
313
- // pending_child_policy_ are non-null). In this case:
314
- // a. If pending_child_policy_->name() equals child_policy_name,
315
- // then we update the existing pending child policy.
316
- // b. If pending_child_policy->name() does not equal
317
- // child_policy_name, then we create a new policy. The new
318
- // policy is stored in pending_child_policy_ (replacing the one
319
- // that was there before, which will be immediately shut down)
320
- // and will later be swapped into child_policy_ by the helper
321
- // when the new child transitions into state READY.
322
- const char* lb_policy_name = lb_policy_config->name();
323
- const bool create_policy =
324
- // case 1
325
- lb_policy_ == nullptr ||
326
- // case 2b
327
- (pending_lb_policy_ == nullptr &&
328
- strcmp(lb_policy_->name(), lb_policy_name) != 0) ||
329
- // case 3b
330
- (pending_lb_policy_ != nullptr &&
331
- strcmp(pending_lb_policy_->name(), lb_policy_name) != 0);
332
- LoadBalancingPolicy* policy_to_update = nullptr;
333
- if (create_policy) {
334
- // Cases 1, 2b, and 3b: create a new child policy.
335
- // If lb_policy_ is null, we set it (case 1), else we set
336
- // pending_lb_policy_ (cases 2b and 3b).
337
- if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
338
- gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this,
339
- lb_policy_ == nullptr ? "" : "pending ", lb_policy_name);
340
- }
341
- auto& lb_policy = lb_policy_ == nullptr ? lb_policy_ : pending_lb_policy_;
342
- lb_policy =
343
- CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings);
344
- policy_to_update = lb_policy.get();
345
- } else {
346
- // Cases 2a and 3a: update an existing policy.
347
- // If we have a pending child policy, send the update to the pending
348
- // policy (case 3a), else send it to the current policy (case 2a).
349
- policy_to_update = pending_lb_policy_ != nullptr ? pending_lb_policy_.get()
350
- : lb_policy_.get();
351
- }
352
- GPR_ASSERT(policy_to_update != nullptr);
353
- // Update the policy.
354
- if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
355
- gpr_log(GPR_INFO, "resolving_lb=%p: Updating %schild policy %p", this,
356
- policy_to_update == pending_lb_policy_.get() ? "pending " : "",
357
- policy_to_update);
358
- }
224
+ Resolver::Result result) {
225
+ // Construct update.
359
226
  UpdateArgs update_args;
360
227
  update_args.addresses = std::move(result.addresses);
361
228
  update_args.config = std::move(lb_policy_config);
362
229
  // TODO(roth): Once channel args is converted to C++, use std::move() here.
363
230
  update_args.args = result.args;
364
231
  result.args = nullptr;
365
- policy_to_update->UpdateLocked(std::move(update_args));
232
+ // Create policy if needed.
233
+ if (lb_policy_ == nullptr) {
234
+ lb_policy_ = CreateLbPolicyLocked(*update_args.args);
235
+ }
236
+ // Update the policy.
237
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
238
+ gpr_log(GPR_INFO, "resolving_lb=%p: Updating child policy %p", this,
239
+ lb_policy_.get());
240
+ }
241
+ lb_policy_->UpdateLocked(std::move(update_args));
366
242
  }
367
243
 
368
244
  // Creates a new LB policy.
369
245
  // Updates trace_strings to indicate what was done.
370
246
  OrphanablePtr<LoadBalancingPolicy>
371
247
  ResolvingLoadBalancingPolicy::CreateLbPolicyLocked(
372
- const char* lb_policy_name, const grpc_channel_args& args,
373
- TraceStringVector* trace_strings) {
374
- ResolvingControlHelper* helper = new ResolvingControlHelper(Ref());
248
+ const grpc_channel_args& args) {
375
249
  LoadBalancingPolicy::Args lb_policy_args;
376
250
  lb_policy_args.combiner = combiner();
377
251
  lb_policy_args.channel_control_helper =
378
- std::unique_ptr<ChannelControlHelper>(helper);
252
+ absl::make_unique<ResolvingControlHelper>(Ref());
379
253
  lb_policy_args.args = &args;
380
254
  OrphanablePtr<LoadBalancingPolicy> lb_policy =
381
- LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
382
- lb_policy_name, std::move(lb_policy_args));
383
- if (GPR_UNLIKELY(lb_policy == nullptr)) {
384
- gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name);
385
- char* str;
386
- gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name);
387
- trace_strings->push_back(str);
388
- return nullptr;
389
- }
390
- helper->set_child(lb_policy.get());
255
+ MakeOrphanable<ChildPolicyHandler>(std::move(lb_policy_args), tracer_);
391
256
  if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
392
- gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)",
393
- this, lb_policy_name, lb_policy.get());
257
+ gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy %p", this,
258
+ lb_policy.get());
394
259
  }
395
- char* str;
396
- gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
397
- trace_strings->push_back(str);
398
260
  grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
399
261
  interested_parties());
400
262
  return lb_policy;
@@ -476,8 +338,8 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
476
338
  }
477
339
  if (lb_policy_config != nullptr) {
478
340
  // Create or update LB policy, as needed.
479
- CreateOrUpdateLbPolicyLocked(std::move(lb_policy_config), std::move(result),
480
- &trace_strings);
341
+ CreateOrUpdateLbPolicyLocked(std::move(lb_policy_config),
342
+ std::move(result));
481
343
  }
482
344
  // Add channel trace event.
483
345
  if (service_config_changed) {
@@ -92,10 +92,9 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
92
92
  void OnResolverError(grpc_error* error);
93
93
  void CreateOrUpdateLbPolicyLocked(
94
94
  RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
95
- Resolver::Result result, TraceStringVector* trace_strings);
95
+ Resolver::Result result);
96
96
  OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
97
- const char* lb_policy_name, const grpc_channel_args& args,
98
- TraceStringVector* trace_strings);
97
+ const grpc_channel_args& args);
99
98
  void MaybeAddTraceMessagesForAddressChangesLocked(
100
99
  bool resolution_contains_addresses, TraceStringVector* trace_strings);
101
100
  void ConcatenateAndAddChannelTraceLocked(
@@ -116,7 +115,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
116
115
 
117
116
  // Child LB policy.
118
117
  OrphanablePtr<LoadBalancingPolicy> lb_policy_;
119
- OrphanablePtr<LoadBalancingPolicy> pending_lb_policy_;
120
118
  };
121
119
 
122
120
  } // namespace grpc_core
@@ -23,6 +23,7 @@
23
23
  #include <cstdlib>
24
24
 
25
25
  #include "absl/strings/str_cat.h"
26
+ #include "absl/strings/str_join.h"
26
27
 
27
28
  #include <grpc/impl/codegen/log.h>
28
29
  #include <grpc/support/alloc.h>
@@ -125,8 +126,11 @@ const char* XdsApi::kCdsTypeUrl = "type.googleapis.com/envoy.api.v2.Cluster";
125
126
  const char* XdsApi::kEdsTypeUrl =
126
127
  "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
127
128
 
128
- XdsApi::XdsApi(const XdsBootstrap::Node* node)
129
- : node_(node),
129
+ XdsApi::XdsApi(XdsClient* client, TraceFlag* tracer,
130
+ const XdsBootstrap::Node* node)
131
+ : client_(client),
132
+ tracer_(tracer),
133
+ node_(node),
130
134
  build_version_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING, " ",
131
135
  grpc_version_string())),
132
136
  user_agent_name_(absl::StrCat("gRPC C-core ", GPR_PLATFORM_STRING)) {}
@@ -289,6 +293,162 @@ envoy_api_v2_DiscoveryRequest* CreateDiscoveryRequest(
289
293
  return request;
290
294
  }
291
295
 
296
+ inline absl::string_view UpbStringToAbsl(const upb_strview& str) {
297
+ return absl::string_view(str.data, str.size);
298
+ }
299
+
300
+ inline void AddStringField(const char* name, const upb_strview& value,
301
+ std::vector<std::string>* fields,
302
+ bool add_if_empty = false) {
303
+ if (value.size > 0 || add_if_empty) {
304
+ fields->emplace_back(
305
+ absl::StrCat(name, ": \"", UpbStringToAbsl(value), "\""));
306
+ }
307
+ }
308
+
309
+ inline void AddLocalityField(int indent_level,
310
+ const envoy_api_v2_core_Locality* locality,
311
+ std::vector<std::string>* fields) {
312
+ std::string indent =
313
+ absl::StrJoin(std::vector<std::string>(indent_level, " "), "");
314
+ // region
315
+ std::string field = absl::StrCat(indent, "region");
316
+ AddStringField(field.c_str(), envoy_api_v2_core_Locality_region(locality),
317
+ fields);
318
+ // zone
319
+ field = absl::StrCat(indent, "zone");
320
+ AddStringField(field.c_str(), envoy_api_v2_core_Locality_zone(locality),
321
+ fields);
322
+ // sub_zone
323
+ field = absl::StrCat(indent, "sub_zone");
324
+ AddStringField(field.c_str(), envoy_api_v2_core_Locality_sub_zone(locality),
325
+ fields);
326
+ }
327
+
328
+ void AddNodeLogFields(const envoy_api_v2_core_Node* node,
329
+ std::vector<std::string>* fields) {
330
+ fields->emplace_back("node {");
331
+ // id
332
+ AddStringField(" id", envoy_api_v2_core_Node_id(node), fields);
333
+ // metadata
334
+ const google_protobuf_Struct* metadata =
335
+ envoy_api_v2_core_Node_metadata(node);
336
+ if (metadata != nullptr) {
337
+ fields->emplace_back(" metadata {");
338
+ size_t num_entries;
339
+ const google_protobuf_Struct_FieldsEntry* const* entries =
340
+ google_protobuf_Struct_fields(metadata, &num_entries);
341
+ for (size_t i = 0; i < num_entries; ++i) {
342
+ fields->emplace_back(" field {");
343
+ // key
344
+ AddStringField(" key",
345
+ google_protobuf_Struct_FieldsEntry_key(entries[i]),
346
+ fields);
347
+ // value
348
+ const google_protobuf_Value* value =
349
+ google_protobuf_Struct_FieldsEntry_value(entries[i]);
350
+ if (value != nullptr) {
351
+ std::string value_str;
352
+ if (google_protobuf_Value_has_string_value(value)) {
353
+ value_str = absl::StrCat(
354
+ "string_value: \"",
355
+ UpbStringToAbsl(google_protobuf_Value_string_value(value)), "\"");
356
+ } else if (google_protobuf_Value_has_null_value(value)) {
357
+ value_str = "null_value: NULL_VALUE";
358
+ } else if (google_protobuf_Value_has_number_value(value)) {
359
+ value_str = absl::StrCat("double_value: ",
360
+ google_protobuf_Value_number_value(value));
361
+ } else if (google_protobuf_Value_has_bool_value(value)) {
362
+ value_str = absl::StrCat("bool_value: ",
363
+ google_protobuf_Value_bool_value(value));
364
+ } else if (google_protobuf_Value_has_struct_value(value)) {
365
+ value_str = "struct_value: <not printed>";
366
+ } else if (google_protobuf_Value_has_list_value(value)) {
367
+ value_str = "list_value: <not printed>";
368
+ } else {
369
+ value_str = "<unknown>";
370
+ }
371
+ fields->emplace_back(absl::StrCat(" value { ", value_str, " }"));
372
+ }
373
+ fields->emplace_back(" }");
374
+ }
375
+ fields->emplace_back(" }");
376
+ }
377
+ // locality
378
+ const envoy_api_v2_core_Locality* locality =
379
+ envoy_api_v2_core_Node_locality(node);
380
+ if (locality != nullptr) {
381
+ fields->emplace_back(" locality {");
382
+ AddLocalityField(2, locality, fields);
383
+ fields->emplace_back(" }");
384
+ }
385
+ // build_version
386
+ AddStringField(" build_version", envoy_api_v2_core_Node_build_version(node),
387
+ fields);
388
+ // user_agent_name
389
+ AddStringField(" user_agent_name",
390
+ envoy_api_v2_core_Node_user_agent_name(node), fields);
391
+ // user_agent_version
392
+ AddStringField(" user_agent_version",
393
+ envoy_api_v2_core_Node_user_agent_version(node), fields);
394
+ // client_features
395
+ size_t num_client_features;
396
+ const upb_strview* client_features =
397
+ envoy_api_v2_core_Node_client_features(node, &num_client_features);
398
+ for (size_t i = 0; i < num_client_features; ++i) {
399
+ AddStringField(" client_features", client_features[i], fields);
400
+ }
401
+ fields->emplace_back("}");
402
+ }
403
+
404
+ void MaybeLogDiscoveryRequest(XdsClient* client, TraceFlag* tracer,
405
+ const envoy_api_v2_DiscoveryRequest* request) {
406
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
407
+ gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
408
+ // TODO(roth): When we can upgrade upb, use upb textformat code to dump
409
+ // the raw proto instead of doing this manually.
410
+ std::vector<std::string> fields;
411
+ // version_info
412
+ AddStringField("version_info",
413
+ envoy_api_v2_DiscoveryRequest_version_info(request),
414
+ &fields);
415
+ // node
416
+ const envoy_api_v2_core_Node* node =
417
+ envoy_api_v2_DiscoveryRequest_node(request);
418
+ if (node != nullptr) AddNodeLogFields(node, &fields);
419
+ // resource_names
420
+ size_t num_resource_names;
421
+ const upb_strview* resource_names =
422
+ envoy_api_v2_DiscoveryRequest_resource_names(request,
423
+ &num_resource_names);
424
+ for (size_t i = 0; i < num_resource_names; ++i) {
425
+ AddStringField("resource_names", resource_names[i], &fields);
426
+ }
427
+ // type_url
428
+ AddStringField("type_url", envoy_api_v2_DiscoveryRequest_type_url(request),
429
+ &fields);
430
+ // response_nonce
431
+ AddStringField("response_nonce",
432
+ envoy_api_v2_DiscoveryRequest_response_nonce(request),
433
+ &fields);
434
+ // error_detail
435
+ const struct google_rpc_Status* error_detail =
436
+ envoy_api_v2_DiscoveryRequest_error_detail(request);
437
+ if (error_detail != nullptr) {
438
+ fields.emplace_back("error_detail {");
439
+ // code
440
+ int32_t code = google_rpc_Status_code(error_detail);
441
+ if (code != 0) fields.emplace_back(absl::StrCat(" code: ", code));
442
+ // message
443
+ AddStringField(" message", google_rpc_Status_message(error_detail),
444
+ &fields);
445
+ fields.emplace_back("}");
446
+ }
447
+ gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s", client,
448
+ absl::StrJoin(fields, "\n").c_str());
449
+ }
450
+ }
451
+
292
452
  grpc_slice SerializeDiscoveryRequest(upb_arena* arena,
293
453
  envoy_api_v2_DiscoveryRequest* request) {
294
454
  size_t output_length;
@@ -305,6 +465,7 @@ grpc_slice XdsApi::CreateUnsupportedTypeNackRequest(const std::string& type_url,
305
465
  upb::Arena arena;
306
466
  envoy_api_v2_DiscoveryRequest* request = CreateDiscoveryRequest(
307
467
  arena.ptr(), type_url.c_str(), /*version=*/"", nonce, error);
468
+ MaybeLogDiscoveryRequest(client_, tracer_, request);
308
469
  return SerializeDiscoveryRequest(arena.ptr(), request);
309
470
  }
310
471
 
@@ -326,6 +487,7 @@ grpc_slice XdsApi::CreateLdsRequest(const std::string& server_name,
326
487
  envoy_api_v2_DiscoveryRequest_add_resource_names(
327
488
  request, upb_strview_make(server_name.data(), server_name.size()),
328
489
  arena.ptr());
490
+ MaybeLogDiscoveryRequest(client_, tracer_, request);
329
491
  return SerializeDiscoveryRequest(arena.ptr(), request);
330
492
  }
331
493
 
@@ -348,6 +510,7 @@ grpc_slice XdsApi::CreateRdsRequest(const std::string& route_config_name,
348
510
  request,
349
511
  upb_strview_make(route_config_name.data(), route_config_name.size()),
350
512
  arena.ptr());
513
+ MaybeLogDiscoveryRequest(client_, tracer_, request);
351
514
  return SerializeDiscoveryRequest(arena.ptr(), request);
352
515
  }
353
516
 
@@ -371,6 +534,7 @@ grpc_slice XdsApi::CreateCdsRequest(const std::set<StringView>& cluster_names,
371
534
  request, upb_strview_make(cluster_name.data(), cluster_name.size()),
372
535
  arena.ptr());
373
536
  }
537
+ MaybeLogDiscoveryRequest(client_, tracer_, request);
374
538
  return SerializeDiscoveryRequest(arena.ptr(), request);
375
539
  }
376
540
 
@@ -394,11 +558,347 @@ grpc_slice XdsApi::CreateEdsRequest(
394
558
  upb_strview_make(eds_service_name.data(), eds_service_name.size()),
395
559
  arena.ptr());
396
560
  }
561
+ MaybeLogDiscoveryRequest(client_, tracer_, request);
397
562
  return SerializeDiscoveryRequest(arena.ptr(), request);
398
563
  }
399
564
 
400
565
  namespace {
401
566
 
567
+ void MaybeLogDiscoveryResponse(XdsClient* client, TraceFlag* tracer,
568
+ const envoy_api_v2_DiscoveryResponse* response) {
569
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
570
+ gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
571
+ // TODO(roth): When we can upgrade upb, use upb textformat code to dump
572
+ // the raw proto instead of doing this manually.
573
+ std::vector<std::string> fields;
574
+ // version_info
575
+ AddStringField("version_info",
576
+ envoy_api_v2_DiscoveryResponse_version_info(response),
577
+ &fields);
578
+ // resources
579
+ size_t num_resources;
580
+ envoy_api_v2_DiscoveryResponse_resources(response, &num_resources);
581
+ fields.emplace_back(
582
+ absl::StrCat("resources: <", num_resources, " element(s)>"));
583
+ // type_url
584
+ AddStringField("type_url",
585
+ envoy_api_v2_DiscoveryResponse_type_url(response), &fields);
586
+ // nonce
587
+ AddStringField("nonce", envoy_api_v2_DiscoveryResponse_nonce(response),
588
+ &fields);
589
+ gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", client,
590
+ absl::StrJoin(fields, "\n").c_str());
591
+ }
592
+ }
593
+
594
+ void MaybeLogRouteConfiguration(
595
+ XdsClient* client, TraceFlag* tracer,
596
+ const envoy_api_v2_RouteConfiguration* route_config) {
597
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
598
+ gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
599
+ // TODO(roth): When we can upgrade upb, use upb textformat code to dump
600
+ // the raw proto instead of doing this manually.
601
+ std::vector<std::string> fields;
602
+ // name
603
+ AddStringField("name", envoy_api_v2_RouteConfiguration_name(route_config),
604
+ &fields);
605
+ // virtual_hosts
606
+ size_t num_virtual_hosts;
607
+ const envoy_api_v2_route_VirtualHost* const* virtual_hosts =
608
+ envoy_api_v2_RouteConfiguration_virtual_hosts(route_config,
609
+ &num_virtual_hosts);
610
+ for (size_t i = 0; i < num_virtual_hosts; ++i) {
611
+ const auto* virtual_host = virtual_hosts[i];
612
+ fields.push_back("virtual_hosts {");
613
+ // name
614
+ AddStringField(
615
+ " name", envoy_api_v2_route_VirtualHost_name(virtual_host), &fields);
616
+ // domains
617
+ size_t num_domains;
618
+ const upb_strview* const domains =
619
+ envoy_api_v2_route_VirtualHost_domains(virtual_host, &num_domains);
620
+ for (size_t j = 0; j < num_domains; ++j) {
621
+ AddStringField(" domains", domains[j], &fields);
622
+ }
623
+ // routes
624
+ size_t num_routes;
625
+ const envoy_api_v2_route_Route* const* routes =
626
+ envoy_api_v2_route_VirtualHost_routes(virtual_host, &num_routes);
627
+ for (size_t j = 0; j < num_routes; ++j) {
628
+ const auto* route = routes[j];
629
+ fields.push_back(" route {");
630
+ // name
631
+ AddStringField(" name", envoy_api_v2_route_Route_name(route),
632
+ &fields);
633
+ // match
634
+ const envoy_api_v2_route_RouteMatch* match =
635
+ envoy_api_v2_route_Route_match(route);
636
+ if (match != nullptr) {
637
+ fields.emplace_back(" match {");
638
+ // path matching
639
+ if (envoy_api_v2_route_RouteMatch_has_prefix(match)) {
640
+ AddStringField(" prefix",
641
+ envoy_api_v2_route_RouteMatch_prefix(match), &fields,
642
+ /*add_if_empty=*/true);
643
+ } else if (envoy_api_v2_route_RouteMatch_has_path(match)) {
644
+ AddStringField(" path",
645
+ envoy_api_v2_route_RouteMatch_path(match), &fields,
646
+ /*add_if_empty=*/true);
647
+ } else if (envoy_api_v2_route_RouteMatch_has_regex(match)) {
648
+ AddStringField(" regex",
649
+ envoy_api_v2_route_RouteMatch_regex(match), &fields,
650
+ /*add_if_empty=*/true);
651
+ } else if (envoy_api_v2_route_RouteMatch_has_safe_regex(match)) {
652
+ fields.emplace_back(" safe_regex: <not printed>");
653
+ } else {
654
+ fields.emplace_back(" <unknown path matching type>");
655
+ }
656
+ // header matching
657
+ size_t num_headers;
658
+ envoy_api_v2_route_RouteMatch_headers(match, &num_headers);
659
+ if (num_headers > 0) {
660
+ fields.emplace_back(
661
+ absl::StrCat(" headers: <", num_headers, " element(s)>"));
662
+ }
663
+ fields.emplace_back(" }");
664
+ }
665
+ // action
666
+ if (envoy_api_v2_route_Route_has_route(route)) {
667
+ const envoy_api_v2_route_RouteAction* action =
668
+ envoy_api_v2_route_Route_route(route);
669
+ fields.emplace_back(" route {");
670
+ if (envoy_api_v2_route_RouteAction_has_cluster(action)) {
671
+ AddStringField(" cluster",
672
+ envoy_api_v2_route_RouteAction_cluster(action),
673
+ &fields);
674
+ } else if (envoy_api_v2_route_RouteAction_has_cluster_header(
675
+ action)) {
676
+ AddStringField(
677
+ " cluster_header",
678
+ envoy_api_v2_route_RouteAction_cluster_header(action), &fields);
679
+ } else if (envoy_api_v2_route_RouteAction_has_weighted_clusters(
680
+ action)) {
681
+ fields.emplace_back(" weighted_clusters: <not printed>");
682
+ }
683
+ fields.emplace_back(" }");
684
+ } else if (envoy_api_v2_route_Route_has_redirect(route)) {
685
+ fields.emplace_back(" redirect: <not printed>");
686
+ } else if (envoy_api_v2_route_Route_has_direct_response(route)) {
687
+ fields.emplace_back(" direct_response: <not printed>");
688
+ } else if (envoy_api_v2_route_Route_has_filter_action(route)) {
689
+ fields.emplace_back(" filter_action: <not printed>");
690
+ }
691
+ fields.push_back(" }");
692
+ }
693
+ fields.push_back("}");
694
+ }
695
+ gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", client,
696
+ absl::StrJoin(fields, "\n").c_str());
697
+ }
698
+ }
699
+
700
+ void MaybeLogCluster(XdsClient* client, TraceFlag* tracer,
701
+ const envoy_api_v2_Cluster* cluster) {
702
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
703
+ gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
704
+ // TODO(roth): When we can upgrade upb, use upb textformat code to dump
705
+ // the raw proto instead of doing this manually.
706
+ std::vector<std::string> fields;
707
+ // name
708
+ AddStringField("name", envoy_api_v2_Cluster_name(cluster), &fields);
709
+ // type
710
+ if (envoy_api_v2_Cluster_has_type(cluster)) {
711
+ fields.emplace_back(
712
+ absl::StrCat("type: ", envoy_api_v2_Cluster_type(cluster)));
713
+ } else if (envoy_api_v2_Cluster_has_cluster_type(cluster)) {
714
+ fields.emplace_back("cluster_type: <not printed>");
715
+ } else {
716
+ fields.emplace_back("<unknown type>");
717
+ }
718
+ // eds_cluster_config
719
+ const envoy_api_v2_Cluster_EdsClusterConfig* eds_cluster_config =
720
+ envoy_api_v2_Cluster_eds_cluster_config(cluster);
721
+ if (eds_cluster_config != nullptr) {
722
+ fields.emplace_back("eds_cluster_config {");
723
+ // eds_config
724
+ const struct envoy_api_v2_core_ConfigSource* eds_config =
725
+ envoy_api_v2_Cluster_EdsClusterConfig_eds_config(eds_cluster_config);
726
+ if (eds_config != nullptr) {
727
+ if (envoy_api_v2_core_ConfigSource_has_ads(eds_config)) {
728
+ fields.emplace_back(" eds_config { ads {} }");
729
+ } else {
730
+ fields.emplace_back(" eds_config: <non-ADS type>");
731
+ }
732
+ }
733
+ // service_name
734
+ AddStringField(" service_name",
735
+ envoy_api_v2_Cluster_EdsClusterConfig_service_name(
736
+ eds_cluster_config),
737
+ &fields);
738
+ fields.emplace_back("}");
739
+ }
740
+ // lb_policy
741
+ fields.emplace_back(
742
+ absl::StrCat("lb_policy: ", envoy_api_v2_Cluster_lb_policy(cluster)));
743
+ // lrs_server
744
+ const envoy_api_v2_core_ConfigSource* lrs_server =
745
+ envoy_api_v2_Cluster_lrs_server(cluster);
746
+ if (lrs_server != nullptr) {
747
+ if (envoy_api_v2_core_ConfigSource_has_self(lrs_server)) {
748
+ fields.emplace_back("lrs_server { self {} }");
749
+ } else {
750
+ fields.emplace_back("lrs_server: <non-self type>");
751
+ }
752
+ }
753
+ gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", client,
754
+ absl::StrJoin(fields, "\n").c_str());
755
+ }
756
+ }
757
+
758
+ void MaybeLogClusterLoadAssignment(
759
+ XdsClient* client, TraceFlag* tracer,
760
+ const envoy_api_v2_ClusterLoadAssignment* cla) {
761
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
762
+ gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
763
+ // TODO(roth): When we can upgrade upb, use upb textformat code to dump
764
+ // the raw proto instead of doing this manually.
765
+ std::vector<std::string> fields;
766
+ // cluster_name
767
+ AddStringField("cluster_name",
768
+ envoy_api_v2_ClusterLoadAssignment_cluster_name(cla),
769
+ &fields);
770
+ // endpoints
771
+ size_t num_localities;
772
+ const struct envoy_api_v2_endpoint_LocalityLbEndpoints* const*
773
+ locality_endpoints =
774
+ envoy_api_v2_ClusterLoadAssignment_endpoints(cla, &num_localities);
775
+ for (size_t i = 0; i < num_localities; ++i) {
776
+ const auto* locality_endpoint = locality_endpoints[i];
777
+ fields.emplace_back("endpoints {");
778
+ // locality
779
+ const auto* locality =
780
+ envoy_api_v2_endpoint_LocalityLbEndpoints_locality(locality_endpoint);
781
+ if (locality != nullptr) {
782
+ fields.emplace_back(" locality {");
783
+ AddLocalityField(2, locality, &fields);
784
+ fields.emplace_back(" }");
785
+ }
786
+ // lb_endpoints
787
+ size_t num_lb_endpoints;
788
+ const envoy_api_v2_endpoint_LbEndpoint* const* lb_endpoints =
789
+ envoy_api_v2_endpoint_LocalityLbEndpoints_lb_endpoints(
790
+ locality_endpoint, &num_lb_endpoints);
791
+ for (size_t j = 0; j < num_lb_endpoints; ++j) {
792
+ const auto* lb_endpoint = lb_endpoints[j];
793
+ fields.emplace_back(" lb_endpoints {");
794
+ // health_status
795
+ uint32_t health_status =
796
+ envoy_api_v2_endpoint_LbEndpoint_health_status(lb_endpoint);
797
+ if (health_status > 0) {
798
+ fields.emplace_back(
799
+ absl::StrCat(" health_status: ", health_status));
800
+ }
801
+ // endpoint
802
+ const envoy_api_v2_endpoint_Endpoint* endpoint =
803
+ envoy_api_v2_endpoint_LbEndpoint_endpoint(lb_endpoint);
804
+ if (endpoint != nullptr) {
805
+ fields.emplace_back(" endpoint {");
806
+ // address
807
+ const auto* address =
808
+ envoy_api_v2_endpoint_Endpoint_address(endpoint);
809
+ if (address != nullptr) {
810
+ fields.emplace_back(" address {");
811
+ // socket_address
812
+ const auto* socket_address =
813
+ envoy_api_v2_core_Address_socket_address(address);
814
+ if (socket_address != nullptr) {
815
+ fields.emplace_back(" socket_address {");
816
+ // address
817
+ AddStringField(
818
+ " address",
819
+ envoy_api_v2_core_SocketAddress_address(socket_address),
820
+ &fields);
821
+ // port_value
822
+ if (envoy_api_v2_core_SocketAddress_has_port_value(
823
+ socket_address)) {
824
+ fields.emplace_back(
825
+ absl::StrCat(" port_value: ",
826
+ envoy_api_v2_core_SocketAddress_port_value(
827
+ socket_address)));
828
+ } else {
829
+ fields.emplace_back(" <non-numeric port>");
830
+ }
831
+ fields.emplace_back(" }");
832
+ } else {
833
+ fields.emplace_back(" <non-socket address>");
834
+ }
835
+ fields.emplace_back(" }");
836
+ }
837
+ fields.emplace_back(" }");
838
+ }
839
+ fields.emplace_back(" }");
840
+ }
841
+ // load_balancing_weight
842
+ const google_protobuf_UInt32Value* lb_weight =
843
+ envoy_api_v2_endpoint_LocalityLbEndpoints_load_balancing_weight(
844
+ locality_endpoint);
845
+ if (lb_weight != nullptr) {
846
+ fields.emplace_back(
847
+ absl::StrCat(" load_balancing_weight { value: ",
848
+ google_protobuf_UInt32Value_value(lb_weight), " }"));
849
+ }
850
+ // priority
851
+ uint32_t priority =
852
+ envoy_api_v2_endpoint_LocalityLbEndpoints_priority(locality_endpoint);
853
+ if (priority > 0) {
854
+ fields.emplace_back(absl::StrCat(" priority: ", priority));
855
+ }
856
+ fields.emplace_back("}");
857
+ }
858
+ // policy
859
+ const envoy_api_v2_ClusterLoadAssignment_Policy* policy =
860
+ envoy_api_v2_ClusterLoadAssignment_policy(cla);
861
+ if (policy != nullptr) {
862
+ fields.emplace_back("policy {");
863
+ // drop_overloads
864
+ size_t num_drop_overloads;
865
+ const envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload* const*
866
+ drop_overloads =
867
+ envoy_api_v2_ClusterLoadAssignment_Policy_drop_overloads(
868
+ policy, &num_drop_overloads);
869
+ for (size_t i = 0; i < num_drop_overloads; ++i) {
870
+ auto* drop_overload = drop_overloads[i];
871
+ fields.emplace_back(" drop_overloads {");
872
+ // category
873
+ AddStringField(
874
+ " category",
875
+ envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload_category(
876
+ drop_overload),
877
+ &fields);
878
+ // drop_percentage
879
+ const auto* drop_percentage =
880
+ envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload_drop_percentage(
881
+ drop_overload);
882
+ if (drop_percentage != nullptr) {
883
+ fields.emplace_back(" drop_percentage {");
884
+ fields.emplace_back(absl::StrCat(
885
+ " numerator: ",
886
+ envoy_type_FractionalPercent_numerator(drop_percentage)));
887
+ fields.emplace_back(absl::StrCat(
888
+ " denominator: ",
889
+ envoy_type_FractionalPercent_denominator(drop_percentage)));
890
+ fields.emplace_back(" }");
891
+ }
892
+ fields.emplace_back(" }");
893
+ }
894
+ // overprovisioning_factor
895
+ fields.emplace_back("}");
896
+ }
897
+ gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s", client,
898
+ absl::StrJoin(fields, "\n").c_str());
899
+ }
900
+ }
901
+
402
902
  // Better match type has smaller value.
403
903
  enum MatchType {
404
904
  EXACT_MATCH,
@@ -449,11 +949,10 @@ MatchType DomainPatternMatchType(const std::string& domain_pattern) {
449
949
  }
450
950
 
451
951
  grpc_error* RouteConfigParse(
952
+ XdsClient* client, TraceFlag* tracer,
452
953
  const envoy_api_v2_RouteConfiguration* route_config,
453
954
  const std::string& expected_server_name, XdsApi::RdsUpdate* rds_update) {
454
- // Strip off port from server name, if any.
455
- size_t pos = expected_server_name.find(':');
456
- std::string expected_host_name = expected_server_name.substr(0, pos);
955
+ MaybeLogRouteConfiguration(client, tracer, route_config);
457
956
  // Get the virtual hosts.
458
957
  size_t size;
459
958
  const envoy_api_v2_route_VirtualHost* const* virtual_hosts =
@@ -490,7 +989,7 @@ grpc_error* RouteConfigParse(
490
989
  continue;
491
990
  }
492
991
  // Skip if match fails.
493
- if (!DomainMatch(match_type, domain_pattern, expected_host_name)) {
992
+ if (!DomainMatch(match_type, domain_pattern, expected_server_name)) {
494
993
  continue;
495
994
  }
496
995
  // Choose this match.
@@ -543,17 +1042,15 @@ grpc_error* RouteConfigParse(
543
1042
  return GRPC_ERROR_NONE;
544
1043
  }
545
1044
 
546
- grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
1045
+ grpc_error* LdsResponseParse(XdsClient* client, TraceFlag* tracer,
1046
+ const envoy_api_v2_DiscoveryResponse* response,
547
1047
  const std::string& expected_server_name,
548
- XdsApi::LdsUpdate* lds_update, upb_arena* arena) {
1048
+ absl::optional<XdsApi::LdsUpdate>* lds_update,
1049
+ upb_arena* arena) {
549
1050
  // Get the resources from the response.
550
1051
  size_t size;
551
1052
  const google_protobuf_Any* const* resources =
552
1053
  envoy_api_v2_DiscoveryResponse_resources(response, &size);
553
- if (size < 1) {
554
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
555
- "LDS response contains 0 resource.");
556
- }
557
1054
  for (size_t i = 0; i < size; ++i) {
558
1055
  // Check the type_url of the resource.
559
1056
  const upb_strview type_url = google_protobuf_Any_type_url(resources[i]);
@@ -593,14 +1090,11 @@ grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
593
1090
  envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_route_config(
594
1091
  http_connection_manager);
595
1092
  XdsApi::RdsUpdate rds_update;
596
- grpc_error* error =
597
- RouteConfigParse(route_config, expected_server_name, &rds_update);
1093
+ grpc_error* error = RouteConfigParse(client, tracer, route_config,
1094
+ expected_server_name, &rds_update);
598
1095
  if (error != GRPC_ERROR_NONE) return error;
599
- lds_update->rds_update.emplace(std::move(rds_update));
600
- const upb_strview route_config_name =
601
- envoy_api_v2_RouteConfiguration_name(route_config);
602
- lds_update->route_config_name =
603
- std::string(route_config_name.data, route_config_name.size);
1096
+ lds_update->emplace();
1097
+ (*lds_update)->rds_update.emplace(std::move(rds_update));
604
1098
  return GRPC_ERROR_NONE;
605
1099
  }
606
1100
  // Validate that RDS must be used to get the route_config dynamically.
@@ -616,26 +1110,24 @@ grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
616
1110
  const upb_strview route_config_name =
617
1111
  envoy_config_filter_network_http_connection_manager_v2_Rds_route_config_name(
618
1112
  rds);
619
- lds_update->route_config_name =
1113
+ lds_update->emplace();
1114
+ (*lds_update)->route_config_name =
620
1115
  std::string(route_config_name.data, route_config_name.size);
621
1116
  return GRPC_ERROR_NONE;
622
1117
  }
623
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
624
- "No listener found for expected server name.");
1118
+ return GRPC_ERROR_NONE;
625
1119
  }
626
1120
 
627
- grpc_error* RdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
1121
+ grpc_error* RdsResponseParse(XdsClient* client, TraceFlag* tracer,
1122
+ const envoy_api_v2_DiscoveryResponse* response,
628
1123
  const std::string& expected_server_name,
629
1124
  const std::string& expected_route_config_name,
630
- XdsApi::RdsUpdate* rds_update, upb_arena* arena) {
1125
+ absl::optional<XdsApi::RdsUpdate>* rds_update,
1126
+ upb_arena* arena) {
631
1127
  // Get the resources from the response.
632
1128
  size_t size;
633
1129
  const google_protobuf_Any* const* resources =
634
1130
  envoy_api_v2_DiscoveryResponse_resources(response, &size);
635
- if (size < 1) {
636
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
637
- "RDS response contains 0 resource.");
638
- }
639
1131
  for (size_t i = 0; i < size; ++i) {
640
1132
  // Check the type_url of the resource.
641
1133
  const upb_strview type_url = google_protobuf_Any_type_url(resources[i]);
@@ -658,27 +1150,24 @@ grpc_error* RdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
658
1150
  if (!upb_strview_eql(name, expected_name)) continue;
659
1151
  // Parse the route_config.
660
1152
  XdsApi::RdsUpdate local_rds_update;
661
- grpc_error* error =
662
- RouteConfigParse(route_config, expected_server_name, &local_rds_update);
1153
+ grpc_error* error = RouteConfigParse(
1154
+ client, tracer, route_config, expected_server_name, &local_rds_update);
663
1155
  if (error != GRPC_ERROR_NONE) return error;
664
- *rds_update = std::move(local_rds_update);
1156
+ rds_update->emplace(std::move(local_rds_update));
665
1157
  return GRPC_ERROR_NONE;
666
1158
  }
667
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
668
- "No route config found for expected name.");
1159
+ return GRPC_ERROR_NONE;
669
1160
  }
670
1161
 
671
- grpc_error* CdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
1162
+ grpc_error* CdsResponseParse(XdsClient* client, TraceFlag* tracer,
1163
+ const envoy_api_v2_DiscoveryResponse* response,
1164
+ const std::set<StringView>& expected_cluster_names,
672
1165
  XdsApi::CdsUpdateMap* cds_update_map,
673
1166
  upb_arena* arena) {
674
1167
  // Get the resources from the response.
675
1168
  size_t size;
676
1169
  const google_protobuf_Any* const* resources =
677
1170
  envoy_api_v2_DiscoveryResponse_resources(response, &size);
678
- if (size < 1) {
679
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
680
- "CDS response contains 0 resource.");
681
- }
682
1171
  // Parse all the resources in the CDS response.
683
1172
  for (size_t i = 0; i < size; ++i) {
684
1173
  XdsApi::CdsUpdate cds_update;
@@ -694,6 +1183,14 @@ grpc_error* CdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
694
1183
  if (cluster == nullptr) {
695
1184
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Can't decode cluster.");
696
1185
  }
1186
+ MaybeLogCluster(client, tracer, cluster);
1187
+ // Ignore unexpected cluster names.
1188
+ upb_strview cluster_name = envoy_api_v2_Cluster_name(cluster);
1189
+ StringView cluster_name_strview(cluster_name.data, cluster_name.size);
1190
+ if (expected_cluster_names.find(cluster_name_strview) ==
1191
+ expected_cluster_names.end()) {
1192
+ continue;
1193
+ }
697
1194
  // Check the cluster_discovery_type.
698
1195
  if (!envoy_api_v2_Cluster_has_type(cluster)) {
699
1196
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("DiscoveryType not found.");
@@ -732,7 +1229,6 @@ grpc_error* CdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
732
1229
  }
733
1230
  cds_update.lrs_load_reporting_server_name.emplace("");
734
1231
  }
735
- upb_strview cluster_name = envoy_api_v2_Cluster_name(cluster);
736
1232
  cds_update_map->emplace(std::string(cluster_name.data, cluster_name.size),
737
1233
  std::move(cds_update));
738
1234
  }
@@ -814,7 +1310,7 @@ grpc_error* LocalityParse(
814
1310
 
815
1311
  grpc_error* DropParseAndAppend(
816
1312
  const envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload* drop_overload,
817
- XdsApi::DropConfig* drop_config, bool* drop_all) {
1313
+ XdsApi::DropConfig* drop_config) {
818
1314
  // Get the category.
819
1315
  upb_strview category =
820
1316
  envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload_category(
@@ -845,13 +1341,13 @@ grpc_error* DropParseAndAppend(
845
1341
  }
846
1342
  // Cap numerator to 1000000.
847
1343
  numerator = GPR_MIN(numerator, 1000000);
848
- if (numerator == 1000000) *drop_all = true;
849
1344
  drop_config->AddCategory(std::string(category.data, category.size),
850
1345
  numerator);
851
1346
  return GRPC_ERROR_NONE;
852
1347
  }
853
1348
 
854
- grpc_error* EdsResponsedParse(
1349
+ grpc_error* EdsResponseParse(
1350
+ XdsClient* client, TraceFlag* tracer,
855
1351
  const envoy_api_v2_DiscoveryResponse* response,
856
1352
  const std::set<StringView>& expected_eds_service_names,
857
1353
  XdsApi::EdsUpdateMap* eds_update_map, upb_arena* arena) {
@@ -859,10 +1355,6 @@ grpc_error* EdsResponsedParse(
859
1355
  size_t size;
860
1356
  const google_protobuf_Any* const* resources =
861
1357
  envoy_api_v2_DiscoveryResponse_resources(response, &size);
862
- if (size < 1) {
863
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
864
- "EDS response contains 0 resource.");
865
- }
866
1358
  for (size_t i = 0; i < size; ++i) {
867
1359
  XdsApi::EdsUpdate eds_update;
868
1360
  // Check the type_url of the resource.
@@ -881,6 +1373,7 @@ grpc_error* EdsResponsedParse(
881
1373
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
882
1374
  "Can't parse cluster_load_assignment.");
883
1375
  }
1376
+ MaybeLogClusterLoadAssignment(client, tracer, cluster_load_assignment);
884
1377
  // Check the cluster name (which actually means eds_service_name). Ignore
885
1378
  // unexpected names.
886
1379
  upb_strview cluster_name = envoy_api_v2_ClusterLoadAssignment_cluster_name(
@@ -903,6 +1396,14 @@ grpc_error* EdsResponsedParse(
903
1396
  if (locality.lb_weight == 0) continue;
904
1397
  eds_update.priority_list_update.Add(locality);
905
1398
  }
1399
+ for (uint32_t priority = 0;
1400
+ priority < eds_update.priority_list_update.size(); ++priority) {
1401
+ auto* locality_map = eds_update.priority_list_update.Find(priority);
1402
+ if (locality_map == nullptr || locality_map->size() == 0) {
1403
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1404
+ "EDS update includes sparse priority list");
1405
+ }
1406
+ }
906
1407
  // Get the drop config.
907
1408
  eds_update.drop_config = MakeRefCounted<XdsApi::DropConfig>();
908
1409
  const envoy_api_v2_ClusterLoadAssignment_Policy* policy =
@@ -915,13 +1416,13 @@ grpc_error* EdsResponsedParse(
915
1416
  policy, &drop_size);
916
1417
  for (size_t j = 0; j < drop_size; ++j) {
917
1418
  grpc_error* error =
918
- DropParseAndAppend(drop_overload[j], eds_update.drop_config.get(),
919
- &eds_update.drop_all);
1419
+ DropParseAndAppend(drop_overload[j], eds_update.drop_config.get());
920
1420
  if (error != GRPC_ERROR_NONE) return error;
921
1421
  }
922
1422
  }
923
1423
  // Validate the update content.
924
- if (eds_update.priority_list_update.empty() && !eds_update.drop_all) {
1424
+ if (eds_update.priority_list_update.empty() &&
1425
+ !eds_update.drop_config->drop_all()) {
925
1426
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
926
1427
  "EDS response doesn't contain any valid "
927
1428
  "locality but doesn't require to drop all calls.");
@@ -937,8 +1438,10 @@ grpc_error* EdsResponsedParse(
937
1438
  grpc_error* XdsApi::ParseAdsResponse(
938
1439
  const grpc_slice& encoded_response, const std::string& expected_server_name,
939
1440
  const std::string& expected_route_config_name,
1441
+ const std::set<StringView>& expected_cluster_names,
940
1442
  const std::set<StringView>& expected_eds_service_names,
941
- LdsUpdate* lds_update, RdsUpdate* rds_update, CdsUpdateMap* cds_update_map,
1443
+ absl::optional<LdsUpdate>* lds_update,
1444
+ absl::optional<RdsUpdate>* rds_update, CdsUpdateMap* cds_update_map,
942
1445
  EdsUpdateMap* eds_update_map, std::string* version, std::string* nonce,
943
1446
  std::string* type_url) {
944
1447
  upb::Arena arena;
@@ -953,6 +1456,7 @@ grpc_error* XdsApi::ParseAdsResponse(
953
1456
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
954
1457
  "Can't decode the whole response.");
955
1458
  }
1459
+ MaybeLogDiscoveryResponse(client_, tracer_, response);
956
1460
  // Record the type_url, the version_info, and the nonce of the response.
957
1461
  upb_strview type_url_strview =
958
1462
  envoy_api_v2_DiscoveryResponse_type_url(response);
@@ -964,17 +1468,19 @@ grpc_error* XdsApi::ParseAdsResponse(
964
1468
  *nonce = std::string(nonce_strview.data, nonce_strview.size);
965
1469
  // Parse the response according to the resource type.
966
1470
  if (*type_url == kLdsTypeUrl) {
967
- return LdsResponseParse(response, expected_server_name, lds_update,
968
- arena.ptr());
1471
+ return LdsResponseParse(client_, tracer_, response, expected_server_name,
1472
+ lds_update, arena.ptr());
969
1473
  } else if (*type_url == kRdsTypeUrl) {
970
- return RdsResponseParse(response, expected_server_name,
1474
+ return RdsResponseParse(client_, tracer_, response, expected_server_name,
971
1475
  expected_route_config_name, rds_update,
972
1476
  arena.ptr());
973
1477
  } else if (*type_url == kCdsTypeUrl) {
974
- return CdsResponseParse(response, cds_update_map, arena.ptr());
1478
+ return CdsResponseParse(client_, tracer_, response, expected_cluster_names,
1479
+ cds_update_map, arena.ptr());
975
1480
  } else if (*type_url == kEdsTypeUrl) {
976
- return EdsResponsedParse(response, expected_eds_service_names,
977
- eds_update_map, arena.ptr());
1481
+ return EdsResponseParse(client_, tracer_, response,
1482
+ expected_eds_service_names, eds_update_map,
1483
+ arena.ptr());
978
1484
  } else {
979
1485
  return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
980
1486
  "Unsupported ADS resource type.");
@@ -983,6 +1489,121 @@ grpc_error* XdsApi::ParseAdsResponse(
983
1489
 
984
1490
  namespace {
985
1491
 
1492
+ void MaybeLogLrsRequest(
1493
+ XdsClient* client, TraceFlag* tracer,
1494
+ const envoy_service_load_stats_v2_LoadStatsRequest* request) {
1495
+ if (GRPC_TRACE_FLAG_ENABLED(*tracer) &&
1496
+ gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) {
1497
+ // TODO(roth): When we can upgrade upb, use upb textformat code to dump
1498
+ // the raw proto instead of doing this manually.
1499
+ std::vector<std::string> fields;
1500
+ // node
1501
+ const auto* node =
1502
+ envoy_service_load_stats_v2_LoadStatsRequest_node(request);
1503
+ if (node != nullptr) {
1504
+ AddNodeLogFields(node, &fields);
1505
+ }
1506
+ // cluster_stats
1507
+ size_t num_cluster_stats;
1508
+ const struct envoy_api_v2_endpoint_ClusterStats* const* cluster_stats =
1509
+ envoy_service_load_stats_v2_LoadStatsRequest_cluster_stats(
1510
+ request, &num_cluster_stats);
1511
+ for (size_t i = 0; i < num_cluster_stats; ++i) {
1512
+ const auto* cluster_stat = cluster_stats[i];
1513
+ fields.emplace_back("cluster_stats {");
1514
+ // cluster_name
1515
+ AddStringField(
1516
+ " cluster_name",
1517
+ envoy_api_v2_endpoint_ClusterStats_cluster_name(cluster_stat),
1518
+ &fields);
1519
+ // cluster_service_name
1520
+ AddStringField(
1521
+ " cluster_service_name",
1522
+ envoy_api_v2_endpoint_ClusterStats_cluster_service_name(cluster_stat),
1523
+ &fields);
1524
+ // upstream_locality_stats
1525
+ size_t num_stats;
1526
+ const envoy_api_v2_endpoint_UpstreamLocalityStats* const* stats =
1527
+ envoy_api_v2_endpoint_ClusterStats_upstream_locality_stats(
1528
+ cluster_stat, &num_stats);
1529
+ for (size_t j = 0; j < num_stats; ++j) {
1530
+ const auto* stat = stats[j];
1531
+ fields.emplace_back(" upstream_locality_stats {");
1532
+ // locality
1533
+ const auto* locality =
1534
+ envoy_api_v2_endpoint_UpstreamLocalityStats_locality(stat);
1535
+ if (locality != nullptr) {
1536
+ fields.emplace_back(" locality {");
1537
+ AddLocalityField(3, locality, &fields);
1538
+ fields.emplace_back(" }");
1539
+ }
1540
+ // total_successful_requests
1541
+ fields.emplace_back(absl::StrCat(
1542
+ " total_successful_requests: ",
1543
+ envoy_api_v2_endpoint_UpstreamLocalityStats_total_successful_requests(
1544
+ stat)));
1545
+ // total_requests_in_progress
1546
+ fields.emplace_back(absl::StrCat(
1547
+ " total_requests_in_progress: ",
1548
+ envoy_api_v2_endpoint_UpstreamLocalityStats_total_requests_in_progress(
1549
+ stat)));
1550
+ // total_error_requests
1551
+ fields.emplace_back(absl::StrCat(
1552
+ " total_error_requests: ",
1553
+ envoy_api_v2_endpoint_UpstreamLocalityStats_total_error_requests(
1554
+ stat)));
1555
+ // total_issued_requests
1556
+ fields.emplace_back(absl::StrCat(
1557
+ " total_issued_requests: ",
1558
+ envoy_api_v2_endpoint_UpstreamLocalityStats_total_issued_requests(
1559
+ stat)));
1560
+ fields.emplace_back(" }");
1561
+ }
1562
+ // total_dropped_requests
1563
+ fields.emplace_back(absl::StrCat(
1564
+ " total_dropped_requests: ",
1565
+ envoy_api_v2_endpoint_ClusterStats_total_dropped_requests(
1566
+ cluster_stat)));
1567
+ // dropped_requests
1568
+ size_t num_drops;
1569
+ const envoy_api_v2_endpoint_ClusterStats_DroppedRequests* const* drops =
1570
+ envoy_api_v2_endpoint_ClusterStats_dropped_requests(cluster_stat,
1571
+ &num_drops);
1572
+ for (size_t j = 0; j < num_drops; ++j) {
1573
+ const auto* drop = drops[j];
1574
+ fields.emplace_back(" dropped_requests {");
1575
+ // category
1576
+ AddStringField(
1577
+ " category",
1578
+ envoy_api_v2_endpoint_ClusterStats_DroppedRequests_category(drop),
1579
+ &fields);
1580
+ // dropped_count
1581
+ fields.emplace_back(absl::StrCat(
1582
+ " dropped_count: ",
1583
+ envoy_api_v2_endpoint_ClusterStats_DroppedRequests_dropped_count(
1584
+ drop)));
1585
+ fields.emplace_back(" }");
1586
+ }
1587
+ // load_report_interval
1588
+ const auto* load_report_interval =
1589
+ envoy_api_v2_endpoint_ClusterStats_load_report_interval(cluster_stat);
1590
+ if (load_report_interval != nullptr) {
1591
+ fields.emplace_back(" load_report_interval {");
1592
+ fields.emplace_back(absl::StrCat(
1593
+ " seconds: ",
1594
+ google_protobuf_Duration_seconds(load_report_interval)));
1595
+ fields.emplace_back(
1596
+ absl::StrCat(" nanos: ",
1597
+ google_protobuf_Duration_nanos(load_report_interval)));
1598
+ fields.emplace_back(" }");
1599
+ }
1600
+ fields.emplace_back("}");
1601
+ }
1602
+ gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s", client,
1603
+ absl::StrJoin(fields, "\n").c_str());
1604
+ }
1605
+ }
1606
+
986
1607
  grpc_slice SerializeLrsRequest(
987
1608
  const envoy_service_load_stats_v2_LoadStatsRequest* request,
988
1609
  upb_arena* arena) {
@@ -1005,6 +1626,7 @@ grpc_slice XdsApi::CreateLrsInitialRequest(const std::string& server_name) {
1005
1626
  arena.ptr());
1006
1627
  PopulateNode(arena.ptr(), node_, build_version_, user_agent_name_,
1007
1628
  server_name, node_msg);
1629
+ MaybeLogLrsRequest(client_, tracer_, request);
1008
1630
  return SerializeLrsRequest(request, arena.ptr());
1009
1631
  }
1010
1632
 
@@ -1117,6 +1739,7 @@ grpc_slice XdsApi::CreateLrsRequest(
1117
1739
  google_protobuf_Duration_set_seconds(load_report_interval, timespec.tv_sec);
1118
1740
  google_protobuf_Duration_set_nanos(load_report_interval, timespec.tv_nsec);
1119
1741
  }
1742
+ MaybeLogLrsRequest(client_, tracer_, request);
1120
1743
  return SerializeLrsRequest(request, arena.ptr());
1121
1744
  }
1122
1745