Generating hash for ring_hash policy (#25415)

pull/25153/head
donnadionne 4 years ago committed by GitHub
parent 27de24a38e
commit 26fd0ce3c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      BUILD
  2. 2
      BUILD.gn
  3. 1
      CMakeLists.txt
  4. 2
      Makefile
  5. 2
      build_autogenerated.yaml
  6. 2
      config.m4
  7. 2
      config.w32
  8. 2
      gRPC-C++.podspec
  9. 3
      gRPC-Core.podspec
  10. 2
      grpc.gemspec
  11. 1
      grpc.gyp
  12. 2
      package.xml
  13. 23
      src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
  14. 27
      src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
  15. 82
      src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
  16. 162
      src/core/ext/xds/xds_api.cc
  17. 24
      src/core/ext/xds/xds_api.h
  18. 1
      src/python/grpcio/grpc_core_dependencies.py
  19. 20
      test/cpp/end2end/xds_end2end_test.cc
  20. 2
      tools/doxygen/Doxyfile.c++.internal
  21. 2
      tools/doxygen/Doxyfile.core.internal

17
BUILD

@ -1611,6 +1611,22 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc_lb_policy_ring_hash",
srcs = [
"src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc",
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h",
],
language = "c++",
deps = [
"grpc_base",
"grpc_client_channel",
"grpc_lb_subchannel_list",
],
)
grpc_cc_library(
name = "grpc_lb_policy_round_robin",
srcs = [
@ -1870,6 +1886,7 @@ grpc_cc_library(
deps = [
"grpc_base",
"grpc_client_channel",
"grpc_lb_policy_ring_hash",
"grpc_xds_client",
],
)

@ -255,6 +255,8 @@ config("grpc_config") {
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc",
"src/core/ext/filters/client_channel/lb_policy/priority/priority.cc",
"src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc",
"src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h",
"src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc",
"src/core/ext/filters/client_channel/lb_policy/subchannel_list.h",
"src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc",

@ -1497,6 +1497,7 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc

@ -1059,6 +1059,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc \
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \
@ -2676,6 +2677,7 @@ ifneq ($(OPENSSL_DEP),)
# installing headers to their final destination on the drive. We need this
# otherwise parallel compilation will fail if a source is compiled first.
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc: $(OPENSSL_DEP)
src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc: $(OPENSSL_DEP)

@ -404,6 +404,7 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
- src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h
@ -910,6 +911,7 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
- src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
- src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
- src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
- src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc
- src/core/ext/filters/client_channel/lb_policy/xds/cds.cc

@ -65,6 +65,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc \
src/core/ext/filters/client_channel/lb_policy/xds/cds.cc \
@ -1038,6 +1039,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/pick_first)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/priority)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/ring_hash)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/round_robin)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/weighted_target)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/xds)

@ -31,6 +31,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\load_balancer_api.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\priority\\priority.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\ring_hash\\ring_hash.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\weighted_target\\weighted_target.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\cds.cc " +
@ -1037,6 +1038,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\priority");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\ring_hash");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\weighted_target");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\xds");

@ -221,6 +221,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h',
@ -859,6 +860,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h',

@ -234,6 +234,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc',
@ -1416,6 +1418,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h',

@ -150,6 +150,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/priority/priority.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc )

@ -480,6 +480,7 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/cds.cc',

@ -130,6 +130,8 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/priority/priority.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc" role="src" />

@ -0,0 +1,23 @@
//
// Copyright 2018 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
namespace grpc_core {
const char* kRequestRingHashAttribute = "request_ring_hash";
} // namespace grpc_core

@ -0,0 +1,27 @@
//
// Copyright 2018 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_RING_HASH_RING_HASH_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_RING_HASH_RING_HASH_H
#include <grpc/support/port_platform.h>
namespace grpc_core {
extern const char* kRequestRingHashAttribute;
} // namespace grpc_core
#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_RING_HASH_RING_HASH_H

@ -26,6 +26,7 @@
#include "xxhash.h"
#include "src/core/ext/filters/client_channel/config_selector.h"
#include "src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/ext/xds/xds_http_filters.h"
@ -524,33 +525,52 @@ void XdsResolver::XdsConfigSelector::MaybeAddCluster(const std::string& name) {
}
}
bool HeaderMatchHelper(const HeaderMatcher& header_matcher,
grpc_metadata_batch* initial_metadata) {
std::string concatenated_value;
absl::optional<absl::string_view> value;
absl::optional<absl::string_view> GetHeaderValue(
grpc_metadata_batch* initial_metadata, absl::string_view header_name,
std::string* concatenated_value) {
// Note: If we ever allow binary headers here, we still need to
// special-case ignore "grpc-tags-bin" and "grpc-trace-bin", since
// they are not visible to the LB policy in grpc-go.
if (absl::EndsWith(header_matcher.name(), "-bin") ||
header_matcher.name() == "grpc-previous-rpc-attempts") {
value = absl::nullopt;
} else if (header_matcher.name() == "content-type") {
value = "application/grpc";
} else {
value = grpc_metadata_batch_get_value(
initial_metadata, header_matcher.name(), &concatenated_value);
if (absl::EndsWith(header_name, "-bin")) {
return absl::nullopt;
} else if (header_name == "content-type") {
return "application/grpc";
}
return header_matcher.Match(value);
return grpc_metadata_batch_get_value(initial_metadata, header_name,
concatenated_value);
}
bool HeadersMatch(const std::vector<HeaderMatcher>& header_matchers,
grpc_metadata_batch* initial_metadata) {
for (const auto& header_matcher : header_matchers) {
if (!HeaderMatchHelper(header_matcher, initial_metadata)) return false;
std::string concatenated_value;
if (!header_matcher.Match(GetHeaderValue(
initial_metadata, header_matcher.name(), &concatenated_value))) {
return false;
}
}
return true;
}
absl::optional<uint64_t> HeaderHashHelper(
const XdsApi::Route::HashPolicy& policy,
grpc_metadata_batch* initial_metadata) {
GPR_ASSERT(policy.type == XdsApi::Route::HashPolicy::HEADER);
std::string value_buffer;
absl::optional<absl::string_view> header_value =
GetHeaderValue(initial_metadata, policy.header_name, &value_buffer);
if (policy.regex != nullptr) {
// If GetHeaderValue() did not already store the value in
// value_buffer, copy it there now, so we can modify it.
if (header_value->data() != value_buffer.data()) {
value_buffer = std::string(*header_value);
}
RE2::GlobalReplace(&value_buffer, *policy.regex, policy.regex_substitution);
header_value = value_buffer;
}
return XXH64(header_value->data(), header_value->size(), 0);
}
bool UnderFraction(const uint32_t fraction_per_million) {
// Generate a random number in [0, 1000000).
const uint32_t random_number = rand() % 1000000;
@ -612,6 +632,38 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig(
XdsResolver* resolver =
static_cast<XdsResolver*>(resolver_->Ref().release());
ClusterState* cluster_state = it->second->Ref().release();
// Generate a hash
absl::optional<uint64_t> hash;
for (const auto& hash_policy : entry.route.hash_policies) {
absl::optional<uint64_t> new_hash;
switch (hash_policy.type) {
case XdsApi::Route::HashPolicy::HEADER:
new_hash = HeaderHashHelper(hash_policy, args.initial_metadata);
break;
case XdsApi::Route::HashPolicy::CHANNEL_ID:
new_hash =
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(resolver));
break;
default:
GPR_ASSERT(0);
}
if (new_hash.has_value()) {
// Rotating the old value prevents duplicate hash rules from cancelling
// each other out and preserves all of the entropy
const uint64_t old_value =
hash.has_value() ? ((hash.value() << 1) | (hash.value() >> 63)) : 0;
hash = old_value ^ new_hash.value();
}
// If the policy is a terminal policy and a hash has been generated,
// ignore the rest of the hash policies.
if (hash_policy.terminal && hash.has_value()) {
break;
}
}
if (!hash.has_value()) {
// If there is no hash, we just choose a random value as a default.
hash = rand();
}
CallConfig call_config;
if (method_config != nullptr) {
call_config.method_configs =
@ -619,6 +671,8 @@ ConfigSelector::CallConfig XdsResolver::XdsConfigSelector::GetCallConfig(
call_config.service_config = std::move(method_config);
}
call_config.call_attributes[kXdsClusterAttribute] = it->first;
call_config.call_attributes[kRequestRingHashAttribute] =
absl::StrFormat("%" PRIu64, hash.value());
call_config.on_call_committed = [resolver, cluster_state]() {
cluster_state->Unref();
ExecCtx::Run(

@ -156,6 +156,83 @@ bool XdsFaultInjectionEnabled() {
return parse_succeeded && parsed_value;
}
//
// XdsApi::Route::HashPolicy
//
XdsApi::Route::HashPolicy::HashPolicy(const HashPolicy& other)
: type(other.type),
header_name(other.header_name),
regex_substitution(other.regex_substitution) {
if (other.regex != nullptr) {
regex =
absl::make_unique<RE2>(other.regex->pattern(), other.regex->options());
}
}
XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=(
const HashPolicy& other) {
type = other.type;
header_name = other.header_name;
if (other.regex != nullptr) {
regex =
absl::make_unique<RE2>(other.regex->pattern(), other.regex->options());
}
regex_substitution = other.regex_substitution;
return *this;
}
XdsApi::Route::HashPolicy::HashPolicy(HashPolicy&& other) noexcept
: type(other.type),
header_name(std::move(other.header_name)),
regex(std::move(other.regex)),
regex_substitution(std::move(other.regex_substitution)) {}
XdsApi::Route::HashPolicy& XdsApi::Route::HashPolicy::operator=(
HashPolicy&& other) noexcept {
type = other.type;
header_name = std::move(other.header_name);
regex = std::move(other.regex);
regex_substitution = std::move(other.regex_substitution);
return *this;
}
bool XdsApi::Route::HashPolicy::HashPolicy::operator==(
const HashPolicy& other) const {
if (type != other.type) return false;
if (type == Type::HEADER) {
if (regex == nullptr) {
if (other.regex != nullptr) return false;
} else {
if (other.regex == nullptr) return false;
return header_name == other.header_name &&
regex->pattern() == other.regex->pattern() &&
regex_substitution == other.regex_substitution;
}
}
return true;
}
std::string XdsApi::Route::HashPolicy::ToString() const {
std::vector<std::string> contents;
switch (type) {
case Type::HEADER:
contents.push_back("type=HEADER");
break;
case Type::CHANNEL_ID:
contents.push_back("type=CHANNEL_ID");
break;
}
contents.push_back(
absl::StrFormat("terminal=%s", terminal ? "true" : "false"));
if (type == Type::HEADER) {
contents.push_back(absl::StrFormat(
"Header %s:/%s/%s", header_name,
(regex == nullptr) ? "" : regex->pattern(), regex_substitution));
}
return absl::StrCat("{", absl::StrJoin(contents, ", "), "}");
}
//
// XdsApi::Route
//
@ -194,6 +271,9 @@ std::string XdsApi::Route::ClusterWeight::ToString() const {
std::string XdsApi::Route::ToString() const {
std::vector<std::string> contents;
contents.push_back(matchers.ToString());
for (const HashPolicy& hash_policy : hash_policies) {
contents.push_back(absl::StrCat("hash_policy=", hash_policy.ToString()));
}
if (!cluster_name.empty()) {
contents.push_back(absl::StrFormat("Cluster name: %s", cluster_name));
}
@ -1468,6 +1548,88 @@ grpc_error* RouteActionParse(const EncodingContext& context,
}
}
}
// Get HashPolicy from RouteAction
if (XdsRingHashEnabled()) {
size_t size = 0;
const envoy_config_route_v3_RouteAction_HashPolicy* const* hash_policies =
envoy_config_route_v3_RouteAction_hash_policy(route_action, &size);
for (size_t i = 0; i < size; ++i) {
const envoy_config_route_v3_RouteAction_HashPolicy* hash_policy =
hash_policies[i];
XdsApi::Route::HashPolicy policy;
policy.terminal =
envoy_config_route_v3_RouteAction_HashPolicy_terminal(hash_policy);
const envoy_config_route_v3_RouteAction_HashPolicy_Header* header;
const envoy_config_route_v3_RouteAction_HashPolicy_FilterState*
filter_state;
if ((header = envoy_config_route_v3_RouteAction_HashPolicy_header(
hash_policy)) != nullptr) {
policy.type = XdsApi::Route::HashPolicy::Type::HEADER;
policy.header_name = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_Header_header_name(
header));
const struct envoy_type_matcher_v3_RegexMatchAndSubstitute*
regex_rewrite =
envoy_config_route_v3_RouteAction_HashPolicy_Header_regex_rewrite(
header);
if (regex_rewrite == nullptr) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but Regex is missing");
continue;
}
const envoy_type_matcher_v3_RegexMatcher* regex_matcher =
envoy_type_matcher_v3_RegexMatchAndSubstitute_pattern(
regex_rewrite);
if (regex_matcher == nullptr) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern is "
"missing");
continue;
}
RE2::Options options;
policy.regex = absl::make_unique<RE2>(
UpbStringToStdString(
envoy_type_matcher_v3_RegexMatcher_regex(regex_matcher)),
options);
if (!policy.regex->ok()) {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier Header with "
"RegexMatchAndSubstitution but RegexMatcher pattern does not "
"compile");
continue;
}
policy.regex_substitution = UpbStringToStdString(
envoy_type_matcher_v3_RegexMatchAndSubstitute_substitution(
regex_rewrite));
} else if ((filter_state =
envoy_config_route_v3_RouteAction_HashPolicy_filter_state(
hash_policy)) != nullptr) {
std::string key = UpbStringToStdString(
envoy_config_route_v3_RouteAction_HashPolicy_FilterState_key(
filter_state));
if (key == "io.grpc.channel_id") {
policy.type = XdsApi::Route::HashPolicy::Type::CHANNEL_ID;
} else {
gpr_log(GPR_DEBUG,
"RouteAction HashPolicy contains policy specifier "
"FilterState but "
"key is not io.grpc.channel_id.");
continue;
}
} else {
gpr_log(
GPR_DEBUG,
"RouteAction HashPolicy contains unsupported policy specifier.");
continue;
}
route->hash_policies.emplace_back(std::move(policy));
}
}
return GRPC_ERROR_NONE;
}

@ -91,7 +91,31 @@ class XdsApi {
std::string ToString() const;
};
struct HashPolicy {
enum Type { HEADER, CHANNEL_ID };
Type type;
bool terminal = false;
// Fields used for type HEADER.
std::string header_name;
std::unique_ptr<RE2> regex = nullptr;
std::string regex_substitution;
HashPolicy() {}
// Copyable.
HashPolicy(const HashPolicy& other);
HashPolicy& operator=(const HashPolicy& other);
// Moveable.
HashPolicy(HashPolicy&& other) noexcept;
HashPolicy& operator=(HashPolicy&& other) noexcept;
bool operator==(const HashPolicy& other) const;
std::string ToString() const;
};
Matchers matchers;
std::vector<HashPolicy> hash_policies;
// Action for this route.
// TODO(roth): When we can use absl::variant<>, consider using that

@ -40,6 +40,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc',
'src/core/ext/filters/client_channel/lb_policy/xds/cds.cc',

@ -5643,8 +5643,6 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderContentType) {
TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
const char* kNewCluster1Name = "new_cluster_1";
const char* kNewEdsService1Name = "new_eds_service_name_1";
const char* kNewCluster2Name = "new_cluster_2";
const char* kNewEdsService2Name = "new_eds_service_name_2";
const size_t kNumEchoRpcs = 100;
SetNextResolution({});
SetNextResolutionForLbChannelAllBalancers();
@ -5655,25 +5653,15 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
AdsServiceImpl::EdsResourceArgs args1({
{"locality0", GetBackendPorts(1, 2)},
});
AdsServiceImpl::EdsResourceArgs args2({
{"locality0", GetBackendPorts(2, 3)},
});
balancers_[0]->ads_service()->SetEdsResource(BuildEdsResource(args));
balancers_[0]->ads_service()->SetEdsResource(
BuildEdsResource(args1, kNewEdsService1Name));
balancers_[0]->ads_service()->SetEdsResource(
BuildEdsResource(args2, kNewEdsService2Name));
// Populate new CDS resources.
Cluster new_cluster1 = default_cluster_;
new_cluster1.set_name(kNewCluster1Name);
new_cluster1.mutable_eds_cluster_config()->set_service_name(
kNewEdsService1Name);
balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
Cluster new_cluster2 = default_cluster_;
new_cluster2.set_name(kNewCluster2Name);
new_cluster2.mutable_eds_cluster_config()->set_service_name(
kNewEdsService2Name);
balancers_[0]->ads_service()->SetCdsResource(new_cluster2);
// Populating Route Configurations for LDS.
RouteConfiguration route_config = default_route_config_;
auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
@ -5682,12 +5670,6 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
header_matcher1->set_name("grpc-foo-bin");
header_matcher1->set_present_match(true);
route1->mutable_route()->set_cluster(kNewCluster1Name);
auto route2 = route_config.mutable_virtual_hosts(0)->add_routes();
route2->mutable_match()->set_prefix("");
auto* header_matcher2 = route2->mutable_match()->add_headers();
header_matcher2->set_name("grpc-previous-rpc-attempts");
header_matcher2->set_present_match(true);
route2->mutable_route()->set_cluster(kNewCluster2Name);
auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
default_route->mutable_match()->set_prefix("");
default_route->mutable_route()->set_cluster(kDefaultClusterName);
@ -5695,7 +5677,6 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
// Send headers which will mismatch each route
std::vector<std::pair<std::string, std::string>> metadata = {
{"grpc-foo-bin", "grpc-foo-bin"},
{"grpc-previous-rpc-attempts", "grpc-previous-rpc-attempts"},
};
WaitForAllBackends(0, 1);
CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_metadata(metadata));
@ -5703,7 +5684,6 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
// were mismatched.
EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
const auto response_state = RouteConfigurationResponseState(0);
EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
}

@ -1086,6 +1086,8 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/lb_policy/subchannel_list.h \
src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc \

@ -911,6 +911,8 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/lb_policy/subchannel_list.h \
src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc \

Loading…
Cancel
Save